unity tipos patron net manejo inyeccion framework dependencias asp c# java dependency-injection inversion-of-control ioc-container

c# - tipos - ¿Cómo evitar la dependencia del constructor de inyección de dependencia?



patron de inyeccion de dependencias c# (9)

¿Qué marco de inyección de dependencia está utilizando? ¿Ha intentado utilizar la inyección basada en incubadora en su lugar?

El beneficio de la inyección basada en el constructor es que parece natural para los programadores de Java que no usan frameworks DI. Necesita 5 cosas para inicializar una clase, entonces tiene 5 argumentos para su constructor. El inconveniente es lo que ha notado, se vuelve difícil de manejar cuando tiene muchas dependencias.

Con Spring, podría pasar los valores requeridos con los configuradores en su lugar y podría usar las anotaciones necesarias para imponer que se inyecten. El inconveniente es que necesita mover el código de inicialización del constructor a otro método y hacer que Spring llame después de inyectar todas las dependencias al marcarlo con @PostConstruct. No estoy seguro de otros marcos, pero supongo que hacen algo similar.

Ambas formas funcionan, es una cuestión de preferencia.

Encuentro que mis constructores están empezando a verse así:

public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )

con cada vez mayor lista de parámetros. Ya que "Container" es mi contenedor de inyección de dependencia, ¿por qué no puedo hacer esto?

public MyClass(Container con)

para cada clase? ¿Cuáles son las desventajas? Si hago esto, siento que estoy usando una estática glorificada. Por favor comparta sus pensamientos sobre la locura de inyección de dependencia y la IoC.


Este es el enfoque que utilizo

public class Hero { [Inject] private IInventory Inventory { get; set; } [Inject] private IArmour Armour { get; set; } [Inject] protected IWeapon Weapon { get; set; } [Inject] private IAction Jump { get; set; } [Inject] private IInstanceProvider InstanceProvider { get; set; } }

Aquí hay un enfoque básico sobre cómo realizar las inyecciones y ejecutar el constructor después de inyectar los valores. Este es un programa totalmente funcional.

public class InjectAttribute : Attribute { } public class TestClass { [Inject] private SomeDependency sd { get; set; } public TestClass() { Console.WriteLine("ctor"); Console.WriteLine(sd); } } public class SomeDependency { } class Program { static void Main(string[] args) { object tc = FormatterServices.GetUninitializedObject(typeof(TestClass)); // Get all properties with inject tag List<PropertyInfo> pi = typeof(TestClass) .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) .Where(info => info.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0).ToList(); // We now happen to know there''s only one dependency so we take a shortcut just for the sake of this example and just set value to it without inspecting it pi[0].SetValue(tc, new SomeDependency(), null); // Find the right constructor and Invoke it. ConstructorInfo ci = typeof(TestClass).GetConstructors()[0]; ci.Invoke(tc, null); } }

Actualmente estoy trabajando en un proyecto de hobby que funciona así https://github.com/Jokine/ToolProject/tree/Core


Inyectar el contenedor es un atajo que finalmente lamentarás.

Sobre inyección no es el problema, generalmente es un síntoma de otros defectos estructurales, especialmente la separación de preocupaciones. Este no es un problema, pero puede tener muchas fuentes y lo que lo hace tan difícil de solucionar es que tendrá que lidiar con todas ellas, a veces al mismo tiempo (piense en desenredar los espaguetis).

Aquí hay una lista incompleta de las cosas a tener en cuenta.

Diseño de dominio deficiente (raíz agregada…. Etc)

Mala separación de inquietudes (Composición del servicio, Comandos, consultas) Consulte CQRS y Event Sourcing.

O Mapeadores (tenga cuidado, estas cosas pueden llevarlo a problemas)

Ver modelos y otros DTO (nunca reutilice uno, y trate de mantenerlos al mínimo !!!!)


La dificultad de pasar en los parámetros no es el problema. El problema es que tu clase está haciendo demasiado, y debería dividirse más.

La inyección de dependencia puede actuar como una advertencia temprana para las clases que se hacen demasiado grandes, especialmente debido al dolor creciente de pasar en todas las dependencias.


Leí todo este hilo dos veces y creo que las personas responden por lo que saben, no por lo que se les pregunta.

La pregunta original de JP parece que está construyendo objetos mediante el envío de un programa de resolución, y luego un montón de clases, pero suponemos que esas clases / objetos son en sí mismos servicios, listos para ser inyectados. ¿Y si no lo son?

JP, si está buscando aprovechar el DI y desear la gloria de mezclar la inyección con datos contextuales, ninguno de estos patrones (o supuestos "anti-patrones") aborda eso específicamente. En realidad se reduce a usar un paquete que lo apoyará en tal esfuerzo.

Container.GetSevice<MyClass>(someObject1, someObject2)

... este formato rara vez es compatible. Creo que la dificultad de programar dicho soporte, sumado al rendimiento miserable que se asociaría con la implementación, lo hace poco atractivo para los desarrolladores de código abierto.

Pero debería hacerse, porque debería poder crear y registrar una fábrica para MyClass''es, y esa fábrica debería poder recibir datos / entradas que no se convierten en un "servicio" solo por el simple hecho de pasar. datos. Si "antipatrón" tiene que ver con consecuencias negativas, entonces forzar la existencia de tipos de servicios artificiales para pasar datos / modelos es ciertamente negativo (a la par con su sentimiento de envolver sus clases en un contenedor. Se aplica el mismo instinto).

Sin embargo, hay un marco que puede ayudar, incluso si se ven un poco feos. Por ejemplo, Ninject:

Creando una instancia usando Ninject con parámetros adicionales en el constructor

Eso es para .NET, es popular y todavía no está tan limpio como debería, pero estoy seguro de que hay algo en cualquier idioma que elijas emplear.


Me encontré con una pregunta similar acerca de la Inyección de dependencia basada en el constructor y lo complejo que era pasar en todas las dependencias.

Uno de los enfoques que he usado en el pasado es usar el patrón de fachada de la aplicación usando una capa de servicio. Esto tendría una API gruesa. Si este servicio depende de los repositorios, usaría una inyección de establecimiento de las propiedades privadas. Esto requiere crear una fábrica abstracta y mover la lógica de crear los repositorios a una fábrica.

Código detallado con explicación se puede encontrar aquí

Mejores prácticas para IoC en la capa de servicio complejo


No creo que los constructores de su clase deban tener una referencia al período de contenedor de IOC. Esto representa una dependencia innecesaria entre su clase y el contenedor (¡el tipo de dependencia que el IOC está tratando de evitar!).


Tiene razón en que si utiliza el contenedor como Localizador de servicios, es más o menos una fábrica estática glorificada. Por muchas razones considero que esto es un anti-patrón .

Uno de los maravillosos beneficios de Constructor Injection es que hace que las violaciones del Principio de Responsabilidad Única sean evidentes.

Cuando eso sucede, es hora de refactorizar los servicios de fachada . En resumen, cree una nueva interfaz de grano más grueso que oculte la interacción entre algunas o todas las dependencias de grano fino que necesita actualmente.


Problema

1) Constructor con cada vez mayor lista de parámetros.

2) Si la clase se hereda (Ej: RepositoryBase ), cambiar la firma del constructor causa un cambio en las clases derivadas.

Solución 1

Pasar el IoC Container al constructor

Por qué

  • No más lista de parámetros cada vez mayor
  • La firma del constructor se vuelve simple

Por qué no

  • Hace que la clase esté bien acoplada al contenedor IoC. (Eso causa problemas cuando 1. quiere usar esa clase en otros proyectos donde usa un contenedor IoC diferente. 2. decide cambiar el contenedor IoC)
  • Te hace la clase menos descriptiva. (No se puede mirar al constructor de la clase y decir lo que necesita para funcionar).
  • La clase puede acceder potencialmente a todos los servicios.

Solucion 2

Crear una clase que agrupe todos los servicios y pasarlo al constructor.

public abstract class EFRepositoryBase { public class Dependency { public DbContext DbContext { get; } public IAuditFactory AuditFactory { get; } public Dependency( DbContext dbContext, IAuditFactory auditFactory) { DbContext = dbContext; AuditFactory = auditFactory; } } protected readonly DbContext DbContext; protected readonly IJobariaAuditFactory auditFactory; protected EFRepositoryBase(Dependency dependency) { DbContext = dependency.DbContext; auditFactory= dependency.JobariaAuditFactory; } }

Clase derivada

public class ApplicationEfRepository : EFRepositoryBase { public new class Dependency : EFRepositoryBase.Dependency { public IConcreteDependency ConcreteDependency { get; } public Dependency( DbContext dbContext, IAuditFactory auditFactory, IConcreteDependency concreteDependency) { DbContext = dbContext; AuditFactory = auditFactory; ConcreteDependency = concreteDependency; } } IConcreteDependency _concreteDependency; public ApplicationEfRepository( Dependency dependency) : base(dependency) { _concreteDependency = dependency.ConcreteDependency; } }

Por qué

  • Agregar una nueva dependencia a la clase no afecta a las clases derivadas
  • La clase es agnóstica de IoC Container
  • La clase es descriptiva (en aspecto de sus dependencias). Por convención, si desea saber de qué clase depende, esa información se acumula en A.Dependency
  • La firma del constructor se vuelve simple

Por qué no

  • Necesito crear clase adicional
  • el registro del servicio se vuelve complejo (es necesario registrar cada X.Dependency separado)
  • Conceptualmente lo mismo que pasar el IoC Container
  • ..

Sin embargo, la Solución 2 es solo un crudo, si hay un argumento sólido en su contra, entonces se agradecería un comentario descriptivo