【问题标题】:Factory Interface in Simple InjectorSimple Injector 中的工厂接口
【发布时间】:2014-03-21 05:36:44
【问题描述】:

我是一名 Ninject 用户,尝试学习 Simple Injector

我在应用程序中经常使用的一个 Ninject 功能是 Factory Interface

这样我可以创建一个这样的接口:

public interface IBarFactory
{
   Bar CreateBar();
}

然后像这样注册它

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

那我就可以简单的使用IBarFactory了,不用创建IBarFactory的实现

我现在尝试在 Simple njector 中找到类似的东西,并找到了this。 但是有了那个方法,我必须实现工厂接口(更多代码)。如果 Bar 对象需要引用另一个对象,我该怎么办?

【问题讨论】:

    标签: c# dependency-injection simple-injector


    【解决方案1】:

    Simple Injector 缺少这种工厂接口工具。这个遗漏背后的想法是,当正确应用依赖注入时,the need for using factories is minimized,这使得此类功能的有用性受到限制。

    在 Simple Injector 中,您必须自己编写一个实现,但这通常是微不足道的。示例:

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

    这个类可以这样注册:

    container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>();
    

    或者 - 如果你很懒 - 你可以注册一个 Func&lt;Bar&gt; 注入如下:

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

    请注意,由于此SimpleInjectorBarFactory 实现依赖于Container 实例,它应该是Composition Root 的一部分,以防止将容器用作Service Locator。通过将类放在 Composition Root 中,它就变成了一个 piece of infrastructure

    所以故意排除了这个特性,但是可以通过使用ResolveUnregisteredType事件来扩展库:

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

    使用上面的扩展方法,你可以为工厂进行注册,方式非常类似于Ninject的注册:

    container.RegisterFactory<IBarFactory>();
    

    就是这样。

    【讨论】:

    • 如果它依赖于容器,你如何对这样的工厂进行单元测试?
    • @Boris:您通常会进行一些单元/集成测试来测试容器的配置(example,因为验证容器is important。按照此处描述的相同方式,您可以测试这个工厂. 由于这些测试测试容器,你显然需要一个初始化的容器。
    • @Steven 我很好奇这里是否有用于您的扩展方法的 dotnet 核心类似物?
    猜你喜欢
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 2018-11-10
    • 1970-01-01
    相关资源
    最近更新 更多