简单注射器中的工厂接口 [英] Factory Interface in Simple Injector

查看:234
本文介绍了简单注射器中的工厂接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名Ninject用户,尝试学习简单注射器



我在应用程序中经常使用的一个Ninject feture是工厂界面



我可以创建一个这样的界面:

  public interface IBarFactory 
{
Bar CreateBar();
}

而且这样注册这个

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

然后我简单可以使用IBarFactory,而不必创建一个IBarFactory的实现



我现在尝试在Simple njector中找到类似的东西,并发现这个
但是,随着这个接触者,我必须实现工厂界面(更多的代码)。如果Bar对象需要引用另一个对象,我该怎么办?

解决方案

Simple Injector缺少工厂界面设备。背后的想法是省略,当正确应用依赖注入时,需要使用工厂最小化,这使得这种功能的有用性受到限制。



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

  private sealed class SimpleInjectorBarFactory:IBarFactory {
private readonly Container container;

public SimpleInjectorBarFactory(Container container){
this.container = container;
}

public Bar CreateBar(){
return this.container.GetInstance< Bar>();
}
}

这个类可以这样注册:

  container.RegisterSingleton< IBarFactory,SimpleInjectorBarFactory>(); 

或者 - 如果你很懒,可以注册一个 Func< Bar> ; 注入如下:

  container.RegisterSingleton< Func< Bar>>(( )=> container.GetInstance< Bar>());注意,由于这个 SimpleInjectorBarFactory 实现依赖于 Container 实例,它应该是组合根,以防止将该容器用作服务定位器。通过将这些类放在您的组织根中,这只是一个一块基础设施



所以功能被故意排除,但是库可以很容易地扩展,以允许这个,有限的代码:

  using System; 
使用System.Linq.Expressions;
使用System.Reflection;
使用System.Runtime.Remoting.Messaging;
使用System.Runtime.Remoting.Proxies;

public static class AutomaticFactoryExtensions {
public static void RegisterFactory< TFactory>(此容器容器){
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();
}

私密密码类AutomaticFactoryProxy:RealProxy {
private readonly Type factoryType;
私人只读容器容器;

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)
返回新的ReturnMessage(this.factoryType,null, 0,null,msg);

if(msg.MethodName ==ToString)
返回新的ReturnMessage(this.factoryType.Name,null,0,null,msg);

var method =(MethodInfo)msg.MethodBase;
object instance = this.container.GetInstance(method.ReturnType);
返回新的ReturnMessage(实例,null,0,null,msg);
}
}
}

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

  container.RegisterFactory< IBarFactory>(); 

就是这样。


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 is omission 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() {
        return 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.RegisterSingleton<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 quite easily to allow this, with a limited amount of code:

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.

这篇关于简单注射器中的工厂接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆