2009-06-30 14 views
9

Al crear un componente designado de .NET, debe proporcionar un constructor predeterminado. Desde el IComponent documentación:Cómo combinar componentes identificables con la inyección de dependencia

siendo un componente, una clase debe implementar la interfaz IComponent y proporcionar un constructor básico que requiere ningún parámetro o un único parámetro de tipo IContainer.

Esto hace que sea imposible hacer la inyección de dependencia a través de los argumentos del constructor. (Constructores adicionales podrían proporcionarse, pero el diseñador se ignoran.) Algunas alternativas que estamos considerando:

  • Servicio de Localización de

    No utilizar la inyección de dependencia, en lugar de utilizar el modelo de servicio de localización para adquirir dependencias. Esto parece ser lo que IComponent.Site. GetService es para. Supongo que podríamos crear una implementación ISite reutilizable (ConfigurableServiceLocator?) Que se puede configurar con las dependencias necesarias. Pero, ¿cómo funciona esto en un contexto de diseñador?

  • inyección de dependencia a través de propiedades

    dependencias Inyectar a través de propiedades. Proporcione las instancias predeterminadas si son necesarias para mostrar el componente en un diseñador . Documente qué propiedades se deben inyectar .

  • dependencias Inyectar con un método Inicializar

    Esto es muy parecido inyección a través de propiedades, pero que mantiene la lista de dependencias que necesitan ser inyectado en un solo lugar. De esta forma, la lista de dependencias requeridas se documenta implícitamente, y el compilador le ayudará con los errores cuando la lista cambie.

¿Alguna idea de cuál es la mejor práctica aquí? ¿Cómo lo haces?


editar: He eliminado "(por ejemplo, un WinForms UserControl)", ya que pretendía la cuestión que se acerca de los componentes en general. Los componentes tienen que ver con la inversión del control (consulte la sección 8.3.1 del UMLv2 specification), por lo tanto, no creo que "no debe inyectar ningún servicio" es una buena respuesta.


edición 2: Tomó un poco de juego con WPF y el patrón MVVM a fin de "obtener" la respuesta de la marca. Ahora veo que los controles visuales son un caso especial. En cuanto al uso de componentes no visuales en las superficies de diseñador, creo que el modelo de componente .NET es fundamentalmente incompatible con la inyección de dependencia. Parece estar diseñado alrededor del patrón de localizador de servicio. Quizás esto comience a cambiar con la infraestructura que se agregó en .NET 4.0 en el espacio de nombres System.ComponentModel.Composition.

Respuesta

6

Esta misma pregunta me molestó durante mucho tiempo hasta que me di cuenta de que estaba pensando en ello de una manera incorrecta.AFAIR, la única razón para crear una implementación IComponent es proporcionar características de tiempo de diseño; no hay efecto en tiempo de ejecución de las implementaciones de IComponent.

Por corrolario, esto significa que debe crear principalmente componentes para implementar funciones de tiempo de diseño. Particularmente para los controles, esto significa que puede configurar el componente para comportarse de cierta manera. Es muy importante darse cuenta de que esta es una preocupación completamente diferente de cómo se comporta realmente el componente o qué datos muestra. No debería tener un comportamiento en el momento del diseño, y tampoco debería contener datos.

Como tal, la restricción en el constructor es en realidad una bendición, ya que le ordena reconsiderar su diseño. Un control es una pieza de software independiente de las fuentes de datos que muestra e interactúa con los datos de una determinada manera. Mientras que los datos se ajusten a ciertas interfaces, etc., el control está contento. Cómo llegan los datos que llegan no conciernen al Control, y tampoco deberían serlo. Sería un error permitir que el Control controle cómo se cargan y modifican los datos.

En WPF, esto es explícitamente mucho más claro que en Windows Forms: le otorga a un Control un DataContext en particular y vincula propiedades del Control a los miembros de ese DataContext. El DataContext (que puede ser cualquier objeto) se origina desde fuera del Control; esa es la responsabilidad o su Capa de presentación.

En Windows Forms, puede hacer lo mismo asignando un contexto de datos a un Control. Esencialmente, esto es Inyección de Propiedades: solo tenga en cuenta que no debe inyectar servicios; debe inyectar datos.

En resumen, no accedería a ninguna de sus sugerencias. En su lugar, permita que el Control tenga una o más propiedades que le permitan asignar datos al Control y utilice el enlace de datos para enlazar con estos datos. Dentro de la implementación del Control, prepárese para manejar la situación en la que no hay datos: esto ocurrirá cada vez que VS controle el Control en tiempo de diseño. El patrón Objeto nulo es muy útil para implementar dicha capacidad de recuperación.

Luego, configure el contexto de datos de sus Controladores. Esa es la forma de MVC de hacerlo: el control es la vista, pero debe tener un controlador separado que pueda instanciar y asignar un modelo a la vista.

+0

Si estoy interpretando su respuesta correctamente, usted está diciendo que los controles no deberían usar ningún servicio. No estoy seguro de estar de acuerdo. Por ejemplo, tengo un control que no representa el texto directamente llamando a System.Windows.Forms.TextRenderer. En cambio, usa un servicio inyectable ITextRenderer (básicamente con los mismos métodos). Esto me permite implementar estrategias de abreviatura sofisticadas más allá de lo que proporciona el framework .NET, al tiempo que mantengo ese código independiente del control en sí mismo. –

+0

Sí, digo que los controles no deberían usar servicios; los servicios deberían usar controles. Un control no debería hacer más que representar UI. Está bien que pueda inyectar estrategias de abreviatura sofisticadas, pero dicha lógica pertenece al Modelo (de Vista), no a la Vista en sí. A continuación, puede vincular su vista a las propiedades en el modelo que produce los valores deseados invocando las dependencias inyectadas. Aunque parece que está utilizando WinForms, consulte esto en busca de inspiración: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx –

Cuestiones relacionadas