簡體   English   中英

Simple Injector 中的工廠接口

[英]Factory Interface in Simple Injector

我是一個試圖學習 Simple Injector 的 Ninject 用戶

我在應用程序中經常使用的一個 Ninject 功能是工廠接口

有了它,我可以創建一個這樣的接口:

public interface IBarFactory
{
   Bar CreateBar();
}

然后像這樣注冊

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

然后我簡單的可以使用IBarFactory,而不必創建IBarFactory的實現

我現在嘗試在 Simple njector 中找到類似的東西,並找到了這個 但是對於那個接近者,我必須實現工廠接口(更多代碼)。 如果 Bar 對象需要對另一個對象的引用,我該怎么辦?

Simple Injector 缺少這個工廠接口工具。 這種省略背后的想法是,當正確應用依賴注入時, 使用工廠的需要被最小化,這使得此類功能的有用性受到限制。

在 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<Bar>注入如下:

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

請注意,由於此SimpleInjectorBarFactory實現依賴於Container實例,因此它應該是Composition Root 的一部分,以防止將 Container 用作Service Locator 通過將類放置在您的Composition Root 中,它就變成了一個基礎設施

所以特意排除了這個特性,但是可以通過使用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>();

就是這樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM