unity net injection framework dependency c# .net dependency-injection dependencies structuremap

c# - net - structuremap registry



¿Structuremap es compatible con Lazy out of the box? (2)

Does structuremap le permite hacer la inyección de constructor de una manera perezosa? ¿Quiere decir que no se crea el objeto que se inyecta hasta que se usa?


Sí, lo hace. La última versión de StructureMap (2.6.x) se compila contra .NET Framework 3.5 y, por lo tanto, no tiene acceso al tipo Lazy<T> introducido en .NET 4. Sin embargo, admite la misma funcionalidad: "no crea el objeto que se inyecta hasta que se usa ". En lugar de depender de un Lazy<T> , dependes de un Func<T> . No se requiere registro especial de contenedor.

He incluido un programa de ejemplo que crea el siguiente resultado:

Created Consumer Consuming Created Helper Helping

Sample.cs:

class Program { static void Main(string[] args) { var container = new Container(x => { x.For<IConsumer>().Use<Consumer>(); x.For<IHelper>().Use<Helper>(); }); var consumer = container.GetInstance<IConsumer>(); consumer.Consume(); } } public class Consumer : IConsumer { private readonly Func<IHelper> _helper; public Consumer(Func<IHelper> helper) { _helper = helper; Console.WriteLine("Created Consumer"); } public void Consume() { Console.WriteLine("Consuming"); _helper().Help(); } } public interface IConsumer { void Consume(); } public interface IHelper { void Help(); } public class Helper : IHelper { public Helper() { Console.WriteLine("Created Helper"); } public void Help() { Console.WriteLine("Helping"); } }


ACTUALIZACIÓN: StructureMap v3 implementa esto de la caja, por lo que este truco ya no es necesario.

La versión 2 de StructureMap no lo hace, pero con algunos trucos puede hacer que haga lo que creo que está buscando. Antes que nada, ya puedes conectar las instancias de Lazy<T> manualmente de esta manera:

container = new Container(x => { x.Scan(y => { y.TheCallingAssembly(); y.WithDefaultConventions(); }); x.For<Lazy<IFoo>>().Use(y => new Lazy<IFoo>(y.GetInstance<Foo>)); x.For<Lazy<IBar>>().Use(y => new Lazy<IBar>(y.GetInstance<Bar>)); x.For<Lazy<IBaz>>().Use(y => new Lazy<IBaz>(y.GetInstance<Baz>)); });

Esto funciona bien, pero debe registrar cada tipo individualmente. Sería más agradable si pudiera aprovechar un enfoque más basado en la convención. Idealmente, la siguiente sintaxis sería agradable.

x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));

Esta sintaxis en realidad funciona ... de alguna manera. Desafortunadamente, en tiempo de ejecución, StructureMap intentará encontrar el constructor "más codicioso" para Lazy<T> y establecerse en public Lazy(Func<T> valueFactory, bool isThreadSafe) . Como no le dijimos qué hacer con el parámetro boolean isThreadSafe, lanzará una excepción cuando intente resolver `Lazy ''.

La documentación de Lazy indica que el "modo de seguridad de subprocesos" del constructor Lazy(Func<T> valueFactory) LazyThreadSafetyMode.ExecutionAndPublication es LazyThreadSafetyMode.ExecutionAndPublication , que resulta ser lo que se obtiene al pasar true al parámetro isThreadSafe del constructor anterior. Entonces, si pudiéramos decirle a StructureMap que pase true por isThreadSafe , obtendríamos el mismo comportamiento que si en primer lugar llamamos al constructor que queríamos usar (por ejemplo, Lazy(Func<T> valueFactory) ).

Simplemente registrando x.For(typeof(bool)).Use(y => true) sería muy imprudente y peligroso ya que le estaríamos diciendo a StructureMap que siga adelante y use el valor true para cualquier booleano en cualquier lugar. En cambio, necesitamos decirle a StructureMap qué valor usar para este solo parámetro booleano, que podemos hacer así.

x.For(typeof(Lazy<>)).Use(typeof(Lazy<>)) .CtorDependency<bool>("isThreadSafe").Is(true);

StructureMap ahora sabe usar el valor de "true" para el parámetro isThreadSafe al resolver Lazy<T> . Ahora podemos usar Lazy<T> en los parámetros del constructor y obtener el comportamiento que creo que estabas buscando.

Puede leer sobre la clase Lazy con más detalle aquí .