C# 简易喷油器的工厂接口
我是一个Ninject用户,尝试学习简单的注入器 我在应用程序中经常使用的一个特性是 有了它,我可以创建如下界面:C# 简易喷油器的工厂接口,c#,dependency-injection,simple-injector,C#,Dependency Injection,Simple Injector,我是一个Ninject用户,尝试学习简单的注入器 我在应用程序中经常使用的一个特性是 有了它,我可以创建如下界面: public interface IBarFactory { Bar CreateBar(); } container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>(); 登记簿是这样写的 kernel.Bind<IBarFactory>().ToFactory(); kerne
public interface IBarFactory
{
Bar CreateBar();
}
container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>();
登记簿是这样写的
kernel.Bind<IBarFactory>().ToFactory();
kernel.Bind().ToFactory();
然后我就可以简单地使用IBarFactory,而不必创建IBarFactory的实现
我现在试图在Simple njector中找到类似的东西,并且已经找到了。
但是有了这个方法,我必须实现工厂接口(更多代码)。如果Bar对象需要对另一个对象的引用,我该怎么办?Simple Injector缺少工厂接口功能。这种省略背后的思想是,当正确应用依赖项注入时,这使得这种特性的有用性受到限制 在SimpleInjector中,您必须自己编写一个实现,但这通常是微不足道的。例如:
private sealed class SimpleInjectorBarFactory : IBarFactory
{
private readonly Container container;
public SimpleInjectorBarFactory(Container container) => this.container = container;
public Bar CreateBar() => this.container.GetInstance<Bar>();
}
使用上述扩展方法,您可以以非常类似于Ninject注册的方式为工厂注册:
container.RegisterFactory<IBarFactory>();
container.RegisterFactory();
就是这样。如果这样的工厂依赖于容器,您如何对其进行单元测试?@Boris:您通常会进行一些单元/集成测试来测试容器的配置(因为正在验证容器。按照这里描述的方法,您可以测试此工厂。由于这些测试测试容器,您显然需要一个初始化的容器。@Steven我很好奇这里是否有一个类似于dotnet core的扩展方法?
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);
}
}
}
container.RegisterFactory<IBarFactory>();