Estoy escribiendo un sistema que subyace a las aplicaciones de programador y que necesita detectar su acceso a ciertos datos. sobre todo por lo que puedo hacer con propiedades, como esto:¿Una forma "elegante" de identificar un campo?
public class NiceClass {
public int x { get; set; }
}
Entonces voy y ajustar el get
y set
descriptores de acceso para que manejan los accesos de manera apropiada. Sin embargo, esto requiere que los usuarios (programadores de aplicaciones) definan todos sus datos como propiedades.
Si los usuarios desean utilizar clases preexistentes que tienen campos "normales" (en lugar de propiedades), no puedo detectar esos accesos. Ejemplo:
public class NotSoNiceClass {
public int y;
}
no puedo detectar accesos a y
. Sin embargo, quiero permitir el uso de clases preexistentes. Como compromiso los usuarios son responsables de notificarme cada vez que se produce un acceso a ese tipo de datos. Por ejemplo:
NotSoNiceClass notSoNice;
...
Write(notSoNice.y, 0); // (as opposed to notSoNice.y = 0;)
Algo así. Créanme, he investigado esto muy a fondo e incluso el análisis directo del bytecode para detectar accesos no es confiable debido a posibles indirecciones, etc. Realmente necesito que los usuarios me notifiquen.
Y ahora mi pregunta: ¿podría recomendarme una forma "elegante" de realizar estas notificaciones? (Sí, sé que toda esta situación no es "elegante" para empezar, estoy tratando de no empeorarla;)). ¿Como lo harias?
Este es un problema para mí, porque en realidad la situación es la siguiente: Tengo la clase siguiente:
public class SemiNiceClass {
public NotSoNiceClass notSoNice { get; set; }
public int z { get; set; }
}
Si el usuario quiere hacer esto:
SemiNiceClass semiNice;
...
semiNice.notSoNice.y = 0;
Deben lugar hacer algo como esto:
semiNice.Write("notSoNice").y = 0;
Dónde Write
volverá un clon de notSoNice
, que es lo que quería que el accesorio set
hiciera de todos modos. Sin embargo, usar una cadena es bastante feo: si más adelante refactorizan el campo, tendrán que pasar por sus accesos Write("notSoNice")
y cambiar la cadena.
¿Cómo podemos identificar el campo? Solo puedo pensar en strings, ints y enums (es decir, ints nuevamente). Pero:
- Ya hemos discutido el problema con las cadenas.
- Los Ints son un dolor. Son aún peores porque el usuario necesita recordar qué int corresponde a cada campo. Refactorizar es igualmente difícil.
- Enums (como
NOT_SO_NICE
yZ
, es decir, los campos deSemiNiceClass
) facilidad refactorización, pero requieren que el usuario escriba una enumeración por clase (SemiNiceClass
, etc), con un valor por campo de la clase. Es molesto. No quiero que me odien;)
Entonces, ¿por qué, oí que preguntas, no podemos hacer esto (abajo)?
semiNice.Write(semiNice.notSoNice).y = 0;
Porque necesito saber qué se está accediendo a campo y semiNice.notSoNice
no identifica un campo. Es el valor del campo, no el campo en sí.
suspiro. Sé que esto es feo. Créanme;)
Agradeceré mucho las sugerencias.
¡Gracias de antemano!
(también, no podía subir con buenas etiquetas para esta pregunta Por favor, hágamelo saber si usted tiene mejores ideas, y voy a editarlos.)
editar # 1: Sugerencia de Hightechrider: Expresiones.
No se si Write(x =>semiNice.y, 0)
estaba destinado a estar basado en las clases que escribí para mi pregunta (SemiNiceClass
, etc.) o si solo es un ejemplo, pero si es el primero no coincide con la estructura: hay no y
campo en SemiNiceClass
. ¿Quería decir Write(x =>semiNice.notSoNice.y, 0)
?
No estoy seguro de cómo se quiere decir para mí utilizar esto ... Voy a publicar el código que he escrito:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test.MagicStrings {
public class MagicStringsTest {
public static void Main(string[] args) {
SemiNiceClass semiNice = new SemiNiceClass();
// The user wants to do: semiNice.notSoNice.y = 50;
semiNice.Write(x => semiNice.notSoNice.y, 50);
}
}
public class SemiNiceClass {
public NotSoNiceClass notSoNice { get; set; }
public int z { get; set; }
public SemiNiceClass() {
notSoNice = new NotSoNiceClass();
}
public void Write(Func<object, object> accessor, object value) {
// Here I'd like to know what field (y, in our example) the user wants to
// write to.
}
}
public class NotSoNiceClass {
public int y;
}
}
¿Cómo consigo que la información en Write
? No puedo encontrar ninguna forma de extraer esa información del Func<,>
. Además, ¿por qué escribir semiNice.Write(x => semiNice.notSoNice.y, 50);
en lugar de semiNice.Write(() => semiNice.notSoNice.y, 50);
, ya que no estamos usando x
para nada?
Gracias.
editar # 2: sugerencia de Hans Passant: la sustitución de campos con propiedades.
Esto es lo que originalmente tenía la intención de hacer, pero volver a compilar no es una opción.
editar # 3: la sugerencia de Ben Hoffstein: proxies dinámicos; LinFu.
Ya he investigado esto por mucho tiempo, y por razones relativamente complejas no puedo usarlo. Sería demasiado largo para explicarlo, pero puedes estar seguro: si pudiera usarlo, lo haría. Es mucho, mucho más limpio que mi solución actual.
He actualizado mi pregunta. Ver EDIT # 1. Gracias :) – Alix
Y actualicé la respuesta por ti. –
Ah, perfecto. +1, y estoy marcando esta respuesta y Akash como las respuestas. Muchas gracias :) – Alix