2010-10-13 8 views
10

que necesita para trabajar en una aplicación que consta de dos partes principales:¿Es una buena práctica usar la reflexión en la lógica de su negocio?

  • La parte lógica de negocio con clases específicas de negocio (por ejemplo, libro, biblioteca, Autor, ...)
  • Una parte genérica que puede mostrar libros, bibliotecas, ... en cuadrículas de datos, asignarlas a una base de datos, ...).

La pieza genérica utiliza la reflexión para sacar los datos de las clases de negocio sin la necesidad de escribir una grilla de datos o lógica de base de datos específica en las clases de negocio. Esto funciona bien y nos permite agregar nuevas clases de negocios (por ejemplo, LibraryMember) sin la necesidad de ajustar la cuadrícula de datos y la lógica de la base de datos.

Sin embargo, a lo largo de los años, se ha agregado un código a las clases de negocios que también utiliza la reflexión para hacer las cosas en las clases de negocios. P.ej. si se cambia el autor de un libro, se llama a los observadores para que le digan al autor que debe agregar este libro a su colección de libros escritos por él (Author.Books). En estos observadores, no solo se pasan las instancias, sino también la información que se deriva directamente de la reflexión (FieldInfo se agrega a la llamada del observador para que la persona que llama sepa que el campo "Autor" del libro se ha modificado).

Puedo ver claramente las ventajas de usar la reflexión en estos módulos genéricos (como la cuadrícula de datos o la interfaz de la base de datos), pero me parece que usar el reflejo en las clases de negocios es una mala idea. Después de todo, ¿no debería funcionar la aplicación sin depender de la reflexión tanto como sea posible? ¿O es el uso de la reflexión la "forma normal de trabajar" en el siglo XXI?

¿Es una buena práctica usar la reflexión en la lógica de su negocio?

EDITAR: Algunas aclaraciones sobre el comentario de Kirk:

  • Imagínese que Autor implementa un observador en el libro.
  • Libro llama a todos sus observadores cuando algún campo de libro cambia (como Título, Año, #Páginas, Autor, ...). El 'FieldInfo' del campo cambiado se pasa en el observador.
  • El Autor-observador luego usa este FieldInfo para decidir si le interesa este cambio. En este caso, si FieldInfo es para el campo Autor del libro, el autor-observador actualizará su propio vector de libros.
+0

Usted dice que se pasa el 'FieldInfo', pero no veo que explique cómo se usa. Concretamente, (aparte de pasar las clases de información, que es relativamente inocua) ¿cómo se usa la reflexión? –

+0

¿Lo usa como la interfaz INotifyPropertyChanged (generalmente se usa en aplicaciones WPF para el enlace de datos)? ¿Subir evento cada vez que se estableció la propiedad, con el nombre de la propiedad? –

+0

@Amittai: No, es una implementación más bien personalizada y muy específica que utiliza la reflexión. – Patrick

Respuesta

5

Evito el uso de la reflexión. Sí, hace que tu programa sea más flexible. Pero esta flexibilidad tiene un alto precio: no hay verificación en tiempo de compilación de los nombres o tipos de campo ni de la información que está recopilando a través de la reflexión.

Como muchas cosas, depende de lo que esté haciendo. Si la naturaleza de tu lógica es que NUNCA comparas los nombres de los campos (o lo que sea) encontrados con un valor constante, entonces usar el reflejo es probablemente algo bueno. Pero si usa la reflexión para buscar nombres de campo y luego recorrerlos buscando los campos llamados "Autor" y "Título", acaba de crear una simulación más compleja de un objeto con dos campos con nombre. ¿Y qué ocurre si busca "Autor" cuando el campo se llama realmente "Nombre del autor", o tiene la intención de buscar "Autor" y escribe "Auhtor" accidentalmente? Ahora tiene errores que no aparecerán hasta el tiempo de ejecución en lugar de estar marcados en tiempo de compilación.

Con los nombres de los campos codificados, su IDE puede decirle en cada lugar que se usa un cierto campo. Con la reflexión ... no es tan fácil de decir. Tal vez puedas hacer una búsqueda de texto en el nombre, pero si los nombres de campo se pasan como variables, puede ser muy difícil.

Estoy trabajando en un sistema ahora donde a los autores originales les encantaron la reflexión y técnicas similares. Hay todo tipo de lugares donde necesitan crear una instancia de una clase y en lugar de simplemente decir "nuevo" y la clase, crean un token que buscan en una tabla para obtener el nombre de la clase. ¿Qué gana esto? Sí, podríamos cambiar la tabla para asignar ese token a un nombre diferente. Y esto nos gana ... ¿qué? ¿Cuándo fue la última vez que dijo: "Oh, cada lugar en el que mi programa crea una instancia de Cliente, quiero cambiar para crear una instancia de NewKindOfCustomer". Si tiene cambios en una clase, cambie la clase, no cree una nueva clase, pero mantenga la antigua para la nostalgia.

Para resolver un problema similar, hago una práctica regular de crear pantallas de entrada de datos sobre la marcha solicitando a la base de datos una lista de nombres de campos, tipos y tamaños, y luego exponiéndola desde allí. Esto me da la ventaja de usar el mismo programa para todas las pantallas de entrada de datos más simples, simplemente pase el nombre de la tabla como parámetro, y si se agrega o elimina un campo, se requiere cero cambio de código. Pero esto solo funciona mientras no me importen los campos. Una vez que empiezo a tener validaciones o efectos secundarios específicos para esta pantalla, el sistema es más problemático de lo que vale, y me conviene recurrir a una codificación más explícita.

3

Tiendo a no utilizar el reflejo donde puedo evitarlo. al usar interfaces y codificación en contra de estos puedo hacer muchas cosas para las cuales algunos usarían la reflexión.

Pero soy un gran admirador de si funciona, funciona.

También mediante el uso del reflejo probablemente tenga algo que se pueda adaptar con bastante facilidad.

Es decir, la única objeción que la mayoría tendría es bastante religiosa ... y si su rendimiento es bueno y el código es fácil de mantener ... ¿a quién le importa?

Editar: Según su edición, utilizaría interfaces para lograr lo que desea. A menos que te malinterprete.

+4

No creo que la * única * objeción sea religiosa. Al estar en C#, algunos de nosotros * disfrutamos * seguridad de tipo estático. :) –

+0

TBH es por eso que uso .net –

2

Creo que es una buena idea mantenerse alejado de Reflection cuando sea posible, pero no tema recurrir a él cuando brinde una solución mejor o más flexible a su problema. El rendimiento alcanzado para cualquier cosa que no sean operaciones de bucle estrechas es probable que sea mínimo en el esquema general de una aplicación o solicitud de formulario web.

Sólo un buen artículo para compartir acerca de la reflexión -

http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/

2

que tienden a utilizar las interfaces en mi capa de negocio y dejar el reflejo de mi capa de presentación. Esto no es absoluto, sino más bien una guía.

9

El principal peligro con Reflection es que la flexibilidad puede convertirse en código desorganizado e inmanejable, especialmente si se utilizan desarrolladores más jóvenes para realizar cambios, que pueden no entender completamente el código Reflection o que están tan enamorados de él que lo usan. para resolver cada problema, incluso cuando las herramientas más simples serían suficientes.

Mi observación ha sido que la generalización excesiva conduce a una complicación excesiva. Se agrava cuando los casos reales de límites resultan no ser acomodados por el diseño generalizado, lo que requiere que los hacks encajen en las nuevas características según lo programado, transmutando la flexibilidad en complejidad.

3

Sobre la base de su edición, parece que usted está utilizando la reflexión puramente como un mecanismo para identificar campos. Esto es opuesto a un comportamiento dinámico como buscando campos, que deben evitarse cuando sea posible (ya que tales búsquedas generalmente usan cadenas que arruinan la seguridad del tipo estático). Usar FieldInfo para proporcionar un identificador para un campo es bastante inofensivo, aunque expone algunas partes internas (la clase de información) de una manera que no es del todo ideal.

Cuestiones relacionadas