C# 简易喷油器的工厂接口

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

我是一个Ninject用户,尝试学习简单的注入器

我在应用程序中经常使用的一个特性是

有了它,我可以创建如下界面:

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>();