I'm a Ninject user that try to learn Simple Injector
One Ninject feture that I often use in my applications is the Factory Interface
With that I can create a Interface like this:
public interface IBarFactory
{
Bar CreateBar();
}
And the register it like this
kernel.Bind<IBarFactory>().ToFactory();
Then I simple can use IBarFactory, and don't have to create a implementation of IBarFactory
I now try to find anything similar in Simple njector, and have found this . But with that approacher, I have to implement the factory interface (more code). And how do I do if the Bar object need a reference to another object?
Simple Injector lacks this a factory interface facility. The idea behind this omission is that when applying Dependency Injection correctly, the need for using factories is minimized , which makes the usefulness of such feature limited.
In Simple Injector you have to write an implementation yourself, but this is usually trivial. Example:
private sealed class SimpleInjectorBarFactory : IBarFactory
{
private readonly Container container;
public SimpleInjectorBarFactory(Container container) => this.container = container;
public Bar CreateBar() => this.container.GetInstance<Bar>();
}
This class can be registered like this:
container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>();
Or -if you're lazy- you can register a Func<Bar>
to be injected as follows:
container.RegisterInstance<Func<Bar>>(() => container.GetInstance<Bar>());
Note that since this SimpleInjectorBarFactory
implementation depends on the Container
instance, it should be part of the Composition Root to prevent using the Container as a Service Locator . By placing the classes inside your Composition Root it becomes merely a piece of infrastructure .
So the feature is excluded deliberately, but the library can be extended by making use of the ResolveUnregisteredType
event:
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);
}
}
}
Using the extension method above, you can do the registration for the factory in a way very similar to Ninject's registration:
container.RegisterFactory<IBarFactory>();
That's it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.