c# dependency-injection inversion-of-control unity-container enterprise-library

c# - Cómo desacoplar la implementación del marco de IoC



dependency-injection inversion-of-control (5)

A DI Container solo se le debe hacer referencia desde Composition Root . Todos los otros módulos no deberían tener referencia al contenedor.

-Mark Seemann (autor de Dependency Injection en .NET )

En otras palabras, solo debería cambiar una clase si cambia los contenedores DI.

La inyección de constructores normalmente es el camino correcto, como han mencionado otros. Puede inyectar interfaces de fábrica o delegados Func<T> si necesita crear objetos sobre la marcha.

También sugiero evitar la configuración XML siempre que sea posible.

He estado aprendiendo IoC, Dependency Injection, etc. y disfrutando el proceso. Los beneficios de desacoplar y programar interfaces son, para mí, una obviedad.

Sin embargo, realmente no me gusta vincularme a un marco específico como Unity, Autofac o Windsor, porque aún estoy aprendiendo y todavía no he decidido cuál es el mejor para mis propósitos.

Entonces, ¿cómo puedo envolver algo como Unity para poder intercambiar fácilmente en Windsor en una fecha posterior? (o lo que sea). Y no te atrevas a decir que usas otro para inyectar el primero;)

¡Gracias!

R.

PD: etiqueté a Unity ya que esa es mi preferencia personal actual (acabo de ver Entlib).


Como algunas otras personas han mencionado, prefieren la inyección de constructor. Esto resolverá muchos de tus problemas.

Si sus clases tienen dependencias directas en el propio contenedor de IoC, tiende a ser una variante del uso del patrón de localización de servicios (anti-). En este caso particular, aísle qué tipos se están resolviendo mediante el localizador de servicios y resuma esa resolución dinámica con una interfaz de fábrica. Entonces, por ejemplo, reemplace esto:

public class Foo { private MyIoCContainer _container; public Foo(MyIoCContainer container) { this._container = container; } public void DoSomething() { // have to do this at runtime for whatever reason var myObj = this._container.Resolve<ISomeType>(); myObj.DoSomething(); myObj.DoSomethingElse(); } }

con este:

public class Foo { private IObjFactory _provider; public Foo(IObjFactory _provider) { this._provider = provider; } public void DoSomething() { var myObj = _provider.GetObj(); myObj.DoSomething(); myObj.DoSomethingElse(); } } public interface IObjFactory { ISomeType GetObj(); }

Ahora tiene una IObjFactory que puede encapsular la naturaleza dinámica de tiempo de ejecución de la construcción de objetos que implementan ISomeType . Si está construyendo muchos tipos diferentes de objetos desde el contenedor / localizador de servicios, entonces debe tener al menos tantas *Factory interfaces de *Factory (de acuerdo con el principio de segregación de interfaz ).



Use la inyección de constructor para comunicar qué dependencias necesita una clase. Todos los contenedores que figuran en la lista lo admiten.

A veces, una parte del código no puede lograr la independencia completa del contenedor, pero estos casos deben ser una parte muy pequeña de su base de código.


Sin duda puede intentar hacer una abstracción del contenedor declarando un IContainer con decir Resolve y Register . Lo hice un par de veces. Luego, seguiría adelante e implementaría un Container: IContainer y encapsularía un contenedor IoC real con su abstracción. Lo intenté con Unity y Castle Windsor.

Pero bueno, pronto me di cuenta de que esto realmente era una sobreingeniería. Luego entendí que traté de abstraerme de la abstracción, pero construir otra abstracción. Esto podría estar bien para aprender el concepto, pero fue un verdadero dolor en el cuello en un proyecto real. Recomiendo encarecidamente contra una abstracción del contenedor IoC. Si usa correctamente el principio de DI, será bastante fácil cambiar su contenedor de todos modos.

El código parece supercomplicado, como

//I did this mess with Service Locator var t = ContainerService.Instance.Resolve<IMyType>(); //others could go further with same Service Locator var t = IoCFactory.Instance.CurrentContainer.Resolve<IMyType>(); //better way, use --> IoC and DI <-- //when a program starts, or a new instance of the context created var t = Container.Resolve<IMyType>() //this lives at the bottom of the stack //and then you just pass IMyType to the constructor of other types //you don''t need to call Resolve again in the logical cycle

Ver esta publicación de Ayende.

Sí, resumieron la inversión del contenedor de control. Creo que si necesitas hacer eso, está bastante claro que realmente no obtienes lo que es el IoC.