tag net microsoft iservicecollection injection extensions dependencyinjection dependency asp c# winforms dependency-injection code-generation inversion-of-control

c# - net - IoC/DI frente a winforms y otro código generado



tag c# (2)

Creo que no hay solución de bala de plata aquí. Yo usaría la inyección de propiedades en este caso para dejar el constructor sin parámetros. Además, personalmente no me gusta la inyección de servicios en las clases de UI, prefiero inyectar algún tipo de presentadores allí. Luego tiene un Presentador de propiedades que se establecerá en el contenedor de IoC y en el configurador de esta propiedad tendrá su código de inicialización.

Fuera de sus dos soluciones, no me gusta la segunda, especialmente debido a que se hace referencia al contenedor IoC en su código, que es IMO incorrecto.

Cuando se utilizan inyección de dependencia (DI) e inversión de control (IoC), los objetos normalmente tendrán un constructor que acepta el conjunto de dependencias necesarias para que el objeto funcione correctamente.

Por ejemplo, si tengo un formulario que requiere un servicio para rellenar un cuadro combinado, es posible que vea algo como esto:

// my files public interface IDataService { IList<MyData> GetData(); } public interface IComboDataService { IList<MyComboData> GetComboData(); } public partial class PopulatedForm : BaseForm { private IDataService service; public PopulatedForm(IDataService service) { //... InitializeComponent(); } }

Esto funciona bien en el nivel superior, solo uso mi contenedor IoC para resolver las dependencias:

var form = ioc.Resolve<PopulatedForm>();

Pero frente al código generado, esto se vuelve más difícil. En winforms se genera un segundo archivo que compone el resto de la clase parcial. Este archivo hace referencia a otros componentes, como los controles personalizados, y utiliza constructores no-args para crear dichos controles:

// generated file: PopulatedForm.Designer.cs public partial class PopulatedForm { private void InitializeComponent() { this.customComboBox = new UserCreatedComboBox(); // customComboBox has an IComboDataService dependency } }

Dado que este es un código generado, no puedo pasar las dependencias y no hay una manera fácil de que mi contenedor IoC inyecte automáticamente todas las dependencias.

Una solución es pasar las dependencias de cada componente secundario a PopulatedForm aunque no las necesite directamente, como en el caso de IComboDataService requerido por UserCreatedComboBox . Luego tengo la responsabilidad de asegurarme de que las dependencias se proporcionen a través de varias propiedades o métodos de establecimiento. Entonces, mi constructor PopulatedForm podría tener el siguiente aspecto:

public PopulatedForm(IDataService service, IComboDataService comboDataService) { this.service = service; InitializeComponent(); this.customComboBox.ComboDataService = comboDataService; }

Otra solución posible es tener el constructor no-args para hacer la resolución necesaria:

public class UserCreatedComboBox { private IComboDataService comboDataService; public UserCreatedComboBox() { if (!DesignMode && IoC.Instance != null) { comboDataService = Ioc.Instance.Resolve<IComboDataService>(); } } }

Ninguna de las soluciones es particularmente buena. ¿Qué patrones y alternativas están disponibles para manejar con más habilidad la inyección de dependencia frente al código generado? Me encantaría ver tanto las soluciones generales, como los patrones, como las específicas de C #, Winforms y Autofac.


Yo diría que su UI, especialmente los subelementos de su UI, no debería necesitar ningún servicio.

Es difícil juzgar qué tan factible es esto para su aplicación, pero MVC o MVP tienen la intención de evitar esta necesidad.

Intentaría rediseñar de manera que un controlador sea responsable de interactuar con los servicios y que el controlador proporcione a los elementos de la vista todo lo que necesitan, en lugar de dejar que los elementos de la vista pidan lo que necesitan.