2009-01-09 10 views

Respuesta

25

El único lugar donde he usado las cosas de Reflection en C# estaba en patrones de fábrica, donde estoy creando objetos (en mi caso, escuchas de red) basados ​​en la información del archivo de configuración. El archivo de configuración proporcionó la ubicación de los ensamblajes, el nombre de los tipos dentro de ellos y cualquier argumento adicional necesario. La fábrica recogió esto y creó a los oyentes según eso.

+0

Hecho lo mismo con una tabla de base de datos - activando nuevas características/desactivando características obsoletas simplemente editando un registro de base de datos ... ¡Me encanta! +1 –

+1

Lo mismo aquí. Básicamente usando Type.GetType seguido de Activator.CreateInstance –

3

No voy a dejar caer ningún patrón, pero sugeriría que es una buena idea evitar el reflejo hasta que realmente lo necesite. Es especialmente útil para situaciones de interoperabilidad y extensibilidad donde no se puede controlar de antemano el tipo de objeto.

11

No sé si es un patrón, pero utilizo la reflexión para generar SQL a partir de las definiciones de clases de DAO.

+1

¿Por qué estás recreando NHibernate? Solo usa el trato real. – yfeldblum

+8

Una de las razones es porque mi DAL es anterior a NHibernate. Consideré cambiar pero no quería lidiar con el desastre de configuración xml. Para mi uso, lo que tengo es mucho más limpio. Pero gracias por la sugerencia. –

8

No existe una regla rígida. Básicamente, no usas la reflexión sin una buena razón. Usa la reflexión cuando no puedas hacer lo que quieras sin ella, o cuando tu código sea mucho más largo o más difícil de entender sin reflexión.

1

Fui por 2 años de desarrollo sin entender el propósito de la reflexión. Tiene usos muy específicos, pero es extremadamente poderoso cuando es la herramienta adecuada para el trabajo.

Creo que lo que estoy tratando de decir es solo utilizarlo cuando esté seguro de que es la única manera de lograr lo que quiere.

32

En un producto en el que estoy trabajando lo usamos mucho, pero Reflection es una bestia compleja y lenta. No busque lugares para usar solo porque suena divertido o interesante. Lo usará cuando se encuentre con un problema que no se puede resolver de otra manera (cargar ensamblajes dinámicamente para plug ins o frameworks, inspección de ensamblaje, fábricas donde no se conocen los tipos en la compilación, etc.). Sin duda vale la pena mirar los tutoriales de reflexión para ver cómo funciona, pero no caiga en la trampa de "tener un martillo y todo lo que parece un clavo". Tiene casos de uso muy especializados.

+7

+1! La reflexión es compleja, lenta y evita la verificación en tiempo de compilación. El uso excesivo hará que su proyecto sea difícil de mantener. –

+8

Lol. Vine aquí con un martillo y todo parecía un clavo. Historia verdadera. –

+0

Gran respuesta, debo decir .... y "tener un martillo y todo lo que parece un clavo" me hizo reír ... Gracias. –

1

Lo uso en un caso similar al mencionado por Harper Shelby, en el cual un archivo de configuración especifica en tiempo de ejecución qué objeto crear. En mi caso particular, no hay nada más elaborado que una fábrica: solo un conjunto de clases que implementan una interfaz común y una función simple que lee el archivo de configuración y crea el objeto adecuado, devolviendo la interfaz.

0

Lo uso con más frecuencia cuando necesito romper la encapsulación de otra persona (generalmente el marco). Es decir, necesito cambiar algún campo privado, o llamar a un método privado, o crear una instancia de alguna clase interna en una biblioteca que no tengo poder para cambiar. Un buen ejemplo es el código en my answer a this question. En este caso, el comportamiento del método marco ServiceBase.Run era inaceptable, por lo que utilicé el reflejo para hacer lo mismo que hace de una manera más aceptable.

La reflexión tiene muchos otros usos, incluso duck typing, que trabaja con attributes y late binding.

+2

Si está rompiendo la encapsulación de otra persona, es probable que lo esté haciendo mal. – abelenky

+0

Al contrario. Normalmente lo estoy haciendo bien porque lo hicieron mal. –

+0

pero todavía está roto, no importa en qué sentido lo mires :) – gbjbaanb

2

Uso la cantidad de reflexión en mis pruebas unitarias, especialmente cuando las cosas que estoy revisando son anónimas. También lo he usado como una forma de clonar/copiar fácilmente objetos modelo. En lugar de escribir el código para hacer esto para cada objeto modelo, puedo crear fácilmente un objeto de un tipo particular usando reflexión, interrogar las propiedades públicas del objeto entrante e invocar a los definidores sobre las propiedades correspondientes de los objetos clonados.También lo uso con clases generadas por diseñadores que implementan las mismas firmas de métodos, pero no tienen una interfaz asociada. En esos casos, puedo interrogar al objeto para ver si tiene el método requerido e invocarlo si lo hace. Las entidades LINQ2SQL son así, así que en mi contexto falso de datos, el método OnSubmit utilizo la reflexión para obtener el método OnValidate y lo invoco para la prueba unitaria.

3

Lo uso en un serializador binario (protobuf-net). Yo uso la reflexión solo para construir el modelo: cuando se usa (es decir, durante la [de] serialización), está utilizando delegados, etc., para obtener el máximo rendimiento.

También lo utilicé (junto con ComponentModel y Reflection.Emit) en HyperDescriptor, para crear acceso de propiedad acelerado (~ 100x la velocidad de reflexión regular).

Y por necesidad, necesita utilizar la reflexión si es building your own Expressions.

2

+1 en el uso de patrones de fábrica - muy potente allí.

Aparte del patrón de la fábrica, cada vez que lo he usado, yo probablemente no debería tener ...

Lo he utilizado para cargar dinámicamente clases que implementan ciertas interfaces (el mío eran los elementos del menú de ensambles) al inicio y realmente lamento ese uso. Desearía haber cargado desde un archivo de configuración (y más tarde agregué un formulario que mostraba las interfaces disponibles para cargar). Es genial pero terriblemente lento ...

Un antipatrón es utilizar las propiedades de acceso que los diseñadores de clase marcaron como privadas sin saber por qué las marcaron como privadas. He hecho esto con el control DataGridView WinForms para desarmar una variable booleana para poder mover una columna "complementaria" cuando se movía su complemento. Una vez más, es genial, pero ese código fallará horriblemente si un nuevo lanzamiento cambia esa propiedad privada (muy bien podría desaparecer en 3.0 o 3.5 ...).

6

encuentro de reflexión (combinado con la carga de clases en tiempo de ejecución) indispensable para plugins de ejecución:

  1. búsqueda de tarros/conjuntos en un lugar conocido
  2. frascos Enumerar/montajes para clases de apoyo a la interfaz de su plugin es compatible con
  3. una instancia del plug-in en tiempo de ejecución
0

reflexión le permite resolver problemas que de otra manera requerirían para duplicar co Delaware. Si te encuentras copiando y pegando código, y no puedes ver cómo un patrón de OO puede ayudar, tal vez si puedes llamarlos, entonces el "equipo de r" puede ayudarte.

Solo bromeando. No pude entender el punto de reflexión por siglos. Si puede escribir código para realizar un trabajo, ¿por qué necesita usar el reflejo?

Supongamos que tiene muchos objetos de la GUI como formularios u objetos 'tabla'. Se une a un objeto de negocio como un cliente:

public class Customer 
{ 
    public string FirstName; 
    public string LastName; 

} 

Sus usuarios no quieren ver los títulos de las columnas FirstName '' o 'Apellido'. Quieren 'Nombre Cristiano' y Apellido. No desea codificar las cadenas literales en todos sus objetos GUI en caso de que cambien de opinión a 'First Name' y 'Father's last name' (lo sé, ejemplo de mierda).

Si define sus atributos de clase usando:

public class Customer 
{ 
    [Description("Christian Name")] 
    public string FirstName; 

    [Description("Surname")] 
    public string LastName; 

} 

Puede utilizar la reflexión para sacar los nombres de columna. Si necesita cambiar el modo todos los objetos de su GUI describen el objeto del cliente, ahora lo hace en un solo lugar.

No tengo conocimiento de ningún antipatrón. Mi consejo es saltar y probarlo. Comenzará a ver todo tipo de formas en que la reflexión le brinda una solución elegante. El rendimiento a menudo se cita como una razón para no usar la relización. Hay una sobrecarga de rendimiento con relfection, pero la descontaría a menos que puedas probar que la sobrecarga está dañando un algoritmo que necesitas.

+0

+1: La reflexión reduce la duplicación de código. -1: la verificación en tiempo de compilación es una razón mucho más importante para no utilizar la reflexión. La reflexión en el ejemplo es parte del marco, no implementada por el desarrollador. Para cualquier reflexión no implementada en el marco, trataría seriamente de repensar mi enfoque. Encontrará que los literales de cadena que contienen código pueden ser tan difíciles de mantener como el código duplicado que intentó evitar. Aquí la generación de código podría ser una buena alternativa. –

+0

En mi humilde opinión, su ejemplo es un antipatrón. El uso del atributo Descripción aquí haría que el manejo de i18n sea casi imposible.No solo tendrías que traducir formas sino también el código. – Nux

8

He utilizado el reflejo en una serie de lugares. Las principales categorías generales incluyen:

  1. GUIs generados-Auto (es decir, un editor de la propiedad). Puede recorrer las propiedades de un objeto y usar un registro de fábricas de elementos de interfaz de usuario para crear un formulario. Uso atributos en propiedades para guiar la creación de UI.
  2. Serialización. He escrito frameworks de serialización, la reflexión de uso para serializar y deserializar objetos.
  3. Servicios web. Similar a la serialización, utilicé la reflexión para crear y consumir mensajes SOAP y también para generar WSDL.
  4. Idiomas específicos del dominio. Los lenguajes de scripting interpretados generalmente se vincularán a los objetos y métodos mediante el uso de la reflexión.
  5. Herramientas de depuración. Dichas herramientas pueden usar la reflexión para examinar el estado de un objeto. Útil para crear mensajes de registro en condiciones de falla.

Patrones sabios, no estoy seguro de cuáles son los patrones. Un hilo común entre todos los usos es la referencia por nombre y enlace tardío: desea enlazar a un miembro en tiempo de ejecución. Este suele ser el caso cuando cargas dinámicamente ensamblajes y no conoces los tipos de objetos que necesitas crear/manipular.

Usar el reflejo es poderoso, pero no lo hará más popular en las fiestas. Úselo únicamente cuando el acoplamiento sea intencionalmente débil. Tan débil que esperas que se rompa en tiempo de ejecución. Un gran ejemplo es el enlace de datos en WPF.

estoy seguro acerca de anti-patrones, pero seguramente se referiría a hacer las cosas en tiempo de ejecución que se debe hacer en tiempo de compilación ...

1

El primer lugar que utilizar la reflexión: Tracción de un tipo de una base de datos.

Tengo una clase que necesita saber a qué biblioteca llamar. Tenga en cuenta que a medida que se agregan nuevas herramientas a la lista, la clase necesita reconocer las nuevas herramientas sin una recompilación, por lo que una declaración de cambio está descartada.

En su lugar, almaceno la cadena de reflexión en el DB que dice a la clase "crear uno de estos ..." Como yo (el programador) siempre aseguro que la clase se deriva de una única clase base, la idea funciona . Es limpio y eficiente.

Pero estoy de acuerdo en que si usa el reflejo para más de estos escenarios de "código generado automáticamente", entonces podría estar abriendo un mundo de dolor cuando se trata de mantener el código en el futuro.

(ingrese la voz del sabio, viejo sabio)
La reflexión viene con un poder increíble ... use el poder con sabiduría.

0

Cuando desee mejorar el rendimiento de los objetos con límite de tiempo. Puede emitir el código necesario para llamar directamente a los tipos encuadernados y luego llamar a través de su método emitido. Aunque no puede realizar llamadas tan rápido como con el enlace anticipado, tendrá un mejor rendimiento que el enlace tardío.

0

Personalmente no lo uso mucho. Tiendo a usarlo cuando no tengo una forma diferente de codificar algo.

Aquí se muestra un ejemplo sencillo:

public static void LogException(Exception exc, string source) 
{ 
    try 
    { 
     // Logic for logging exceptions 
    } 
    catch(Exception ex) 
    { 
     //If logging fails for some reason 
     //then we still log it using reflection 
     LogException(ex, "Error while logging an exception"); 
    } 
} 
Cuestiones relacionadas