simpleinjector simple injector example container c# dependency-injection simple-injector

c# - example - simple injector container



Interfaz de fábrica en inyector simple (1)

Soy un usuario de Ninject que intento aprender Simple Injector

Una característica de Ninject que a menudo uso en mis aplicaciones es la interfaz de fábrica

Con eso puedo crear una interfaz como esta:

public interface IBarFactory { Bar CreateBar(); }

Y el registro es así

kernel.Bind<IBarFactory>().ToFactory();

Entonces, simple, puedo usar IBarFactory, y no tengo que crear una implementación de IBarFactory

Ahora trato de encontrar algo similar en Simple njector, y he encontrado esto . Pero con ese enfoque, tengo que implementar la interfaz de fábrica (más código). ¿Y cómo hago si el objeto Bar necesita una referencia a otro objeto?


Simple Injector carece de esta función de interfaz de fábrica. La idea subyacente es la omisión de que al aplicar la Inyección de Dependencia correctamente, se minimiza la necesidad de utilizar fábricas , lo que limita la utilidad de dicha función.

En Simple Injector tienes que escribir una implementación tú mismo, pero esto generalmente es trivial. Ejemplo:

private sealed class SimpleInjectorBarFactory : IBarFactory { private readonly Container container; public SimpleInjectorBarFactory(Container container) { this.container = container; } public Bar CreateBar() { return this.container.GetInstance<Bar>(); } }

Esta clase puede registrarse así:

container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>();

O, si eres perezoso, puedes registrar un Func<Bar> para inyectarlo de la siguiente manera:

container.RegisterSingleton<Func<Bar>>(() => container.GetInstance<Bar>());

Tenga en cuenta que, dado que esta implementación de SimpleInjectorBarFactory depende de la instancia de Container , debe ser parte de la raíz de composición para evitar el uso del contenedor como un localizador de servicio . Al colocar las clases dentro de su Composition Root, se convierte simplemente en una pieza de infraestructura .

Por lo tanto, la característica se excluye deliberadamente, pero la biblioteca se puede ampliar con bastante facilidad para permitir esto, con una cantidad limitada de código:

using System; using System.Linq.Expressions; using System.Reflection; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Proxies; public static class AutomaticFactoryExtensions { public static void RegisterFactory<TFactory>(this Container container) { if (!typeof(TFactory).IsInterface) throw new ArgumentException(typeof(TFactory).Name + " is no interface"); container.ResolveUnregisteredType += (s, e) => { if (e.UnregisteredServiceType == typeof(TFactory)) { e.Register(Expression.Constant( value: CreateFactory(typeof(TFactory), container), type: typeof(TFactory))); } }; } private static object CreateFactory(Type factoryType, Container container) { var proxy = new AutomaticFactoryProxy(factoryType, container); return proxy.GetTransparentProxy(); } private sealed class AutomaticFactoryProxy : RealProxy { private readonly Type factoryType; private readonly Container container; public AutomaticFactoryProxy(Type factoryType, Container container) : base(factoryType) { this.factoryType = factoryType; this.container = container; } public override IMessage Invoke(IMessage msg) { if (msg is IMethodCallMessage) { return this.InvokeFactory(msg as IMethodCallMessage); } return msg; } private IMessage InvokeFactory(IMethodCallMessage msg) { if (msg.MethodName == "GetType") return new ReturnMessage(this.factoryType, null, 0, null, msg); if (msg.MethodName == "ToString") return new ReturnMessage(this.factoryType.Name, null, 0, null, msg); var method = (MethodInfo)msg.MethodBase; object instance = this.container.GetInstance(method.ReturnType); return new ReturnMessage(instance, null, 0, null, msg); } } }

Usando el método de extensión anterior, puede hacer el registro para la fábrica de una manera muy similar al registro de Ninject:

container.RegisterFactory<IBarFactory>();

Eso es.