2009-06-24 9 views
15

Revisé todas las publicaciones en reflection pero no pude encontrar la respuesta a mi pregunta.¿Qué problemas resuelve la reflexión?

¿Cuáles fueron los problemas en el mundo de la programación antes de que surgiera .NET reflection y cómo resolvió esos problemas?

Por favor explique con un ejemplo.

+2

@Praveen: esta es una pregunta bastante amplia. ¿Puedes ser mas específico? –

+0

Actualmente no es una pregunta real: imposible de responder. Tal vez si se expandió con lo que está tratando de determinar. – Richard

+0

¿Es esta tarea? – erikkallen

Respuesta

14

Debe decirse que la reflexión de .NET no es revolucionaria; los conceptos han existido en otros marcos.

Reflexión en .NET tiene 2 facetas:

Investigación de información de tipo

Sin algún tipo de API de reflexión/introspección, se hace muy difícil de realizar cosas como la serialización. En lugar de tener esto provisto en tiempo de ejecución (al inspeccionar las propiedades/campos/etc), a menudo necesita generación de código, es decir, un código que explícitamente sabe cómo serializar cada uno de sus tipos. Es tedioso y doloroso si quieres serializar algo que no tiene un gemelo.

Del mismo modo, no hay ningún lugar para almacenar metadatos adicionales sobre las propiedades, etc., por lo que terminará teniendo muchos códigos adicionales o archivos de configuración externos. Algo tan simple como poder asociar un nombre descriptivo con una propiedad (a través de un atributo) es una gran victoria para el código UI.

Metaprogramación

.NET reflexión también proporciona un mecanismo para crear tipos (etc) en tiempo de ejecución, lo cual es muy poderosa para algunos escenarios específicos; las alternativas son:

  • se extiende esencialmente un árbol analizador/lógica en tiempo de ejecución (en lugar de compilar la lógica en tiempo de ejecución en código ejecutable) - mucho más lento
  • aún más la generación de código - yay!
9

Creo que para entender la necesidad de reflexión en .NET, necesitamos volver a .NET. Después de todo, los lenguajes modernos como Java y C# no tienen un historial BF (antes de la reflexión).

C++ podría decirse que ha tenido la mayor influencia en C# y Java. Pero C++ originalmente no tenía reflejo y codificamos sin él y logramos salir adelante. Ocasionalmente teníamos un puntero de vacío y usábamos un molde para forzarlo en el tipo que quisiéramos. El problema aquí es que el elenco podría fallar con consecuencias terribles:

double CalculateSize(void* rectangle) { 
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight()); 
} 

Ahora hay un montón de argumentos por los que no debería haber codificados a ti mismo en este problema en primer lugar. Pero el problema no es muy diferente de .NET 1.1 con C# cuando no teníamos genéricos:

Hashtable shapes = new Hashtable(); 
.... 
double CalculateSize(object shape) { 
    return ((Rect)shape).Width * ((Rect)shape).Height; 
} 

Sin embargo, cuando el ejemplo de C# no lo hace con una excepción más que un volcado de memoria potencial.

Cuando se agregó la reflexión a C++ (conocida como Identificación del tipo de tiempo de ejecución o RTTI), se debatió acaloradamente.En el libro de Stroustrup El Diseño y Evolución de C++, que enumera los siguientes argumentos en contra de RTTI, en el que algunas personas:

Declared the support unnecessary 
Declared the new style inherently evil ("against the spirit of C++") 
Deemed it too expensive 
Thought it too complicated and confusing 
Saw it as the beginning of an avalanche of new features 

Pero nos permitió para consultar el tipo de objetos o características de objetos. Por ejemplo (usando C#)

Hashtable shapes = new Hashtable(); 
.... 
double CalculateSize(object shape) { 
    if(shape is Rect) { 
     return ((Rect)shape).Width * ((Rect)shape).Height; 
    } 
    else if(shape is Circle) { 
     return Math.Power(((Circle)shape).Radius, 2.0) * Math.PI; 
    } 
} 

Por supuesto, con la planificación adecuada este ejemplo nunca debería tener que ocurrir.

Así, las situaciones del mundo real, donde he necesitado que incluyen:

  • objetos de Acceso a la memoria compartida, todo lo que tengo es un puntero y tengo que decidir qué hacer con él.
  • cargando dinámicamente ensamblajes, piense en NUnit donde carga cada ensamblaje y utiliza la reflexión para determinar qué clases son accesorios de prueba.
  • Tener un conjunto mixto de objetos en un Hashtable y querer procesarlos de manera diferente en un enumerador.
  • Muchos otros ...

Por lo tanto, me gustaría ir tan lejos como para argumentar que la reflexión no ha permitido la posibilidad de hacer algo que no se podía hacer antes. Sin embargo, hace que algunos tipos de problemas sean más fáciles de codificar, más claros para el lector, más cortos para escribir, etc.

Por supuesto, esa es solo mi opinión, podría estar equivocado.

1

vez quería tener pruebas de unidad en un archivo de texto que puede ser modificado por un usuario no técnico en el formato en C++:

MyObj Function args //textfile.txt 

pero no pude encontrar una manera de leer en una cadena y luego hacer que el código cree una instancia de objeto del tipo representado por la cadena sin reflexión que C++ no admite.

char *str; //read in some type from a text file say the string is "MyObj" 
str *obj; //cast a pointer as type MyObj 
obj = new str; //create a MyObj 

Otro uso podría ser la de tener una función de copia genérica que podrían copiar los miembros de una clase sin saber de antemano.

0

Ayuda mucho cuando usa atributos de C# como [Obsoleto] o [Serializable] en su código. Los marcos como NUnit usan la reflexión en las clases y contienen métodos para comprender qué métodos son las pruebas, la configuración, el desmontaje, etc.

Cuestiones relacionadas