如何使用Autofac注入同一对象的两个实例? [英] How to inject two instances of same object using Autofac?

查看:205
本文介绍了如何使用Autofac注入同一对象的两个实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Autofac构造函数注入.我需要弄清楚如何将一个对象实例注入多个构造函数参数中,而无需在容器设置阶段明确解析每个参数.

I'm using Autofac constructor injection. I need to figure out how to inject a single object instance into more than one constructor argument, without needing to explicitly resolve each argument during the container setup phase.

我有一个复杂的场景,此行为可以简化此场景;下面的示例只是一个简化的场景,因此我可以演示所需的行为.

I have a complex scenario which would be simplified by this behavior; the following example is just a simplified scenario so I can demonstrate the behavior I'm looking for.

示例:

说我有IOpenable和ICloseable这两个接口:

public interface IOpenable
{
    void Open();
}
public interface ICloseable
{
    void Close();
}

我有这个Door类,实现了它们两者:

public interface IDoor : IOpenable, ICloseable { }
public class Door : IDoor, IOpenable, ICloseable 
{
    void Open() { ... }
    void Close() { ... }
}

我有一个接受IOpenable和ICloseable的类:

public class DoorHandler : IDoorHandler
{
    public DoorHandler(IOpenable openable, ICloseable closeable)
    {
        ...
    }
    ...
}

问题:

当IOpenable和ICloseable都是同一个构造函数中的依赖项时,是否可以告诉autofac将 same Door对象注入这两个参数中?

Is it possible to tell autofac to inject the same Door object into both arguments whenever both an IOpenable and ICloseable are dependencies in the same constructor?

注意:我不能做:

container.Register<IDoorHandler>( c => {
    Door d = c.Resolve<IDoor>();
    return new DoorHandler(d,d)
});

做我想做的事,但是请记住,这个DoorHandler类只是一个例子.在我的真实代码中,"DoorHandler"实际上是一个MVC控制器,我正在用RegisterControllers()注册它.所以我不能像上面那样注册.此外,有时依赖图可能会变得过于复杂,在每种情况下明确地执行此操作可能会变得不堪重负.

That would do what I want, but remember that this DoorHandler class is just an example. In my real code, the "DoorHandler" is really an MVC Controller and I'm registering it with RegisterControllers(). So I can't register it like the above. Besides, sometimes dependency graphs can get overly complex and doing this explicitly in every case can become overwhelming.

我想我正在寻找的是能够做类似的事情:

I guess what I'm looking for is to be able to do something like:

container.RegisterType<DoorHandler>().As<IDoorHandler>();
container.RegisterType<Door>().As<IDoor>();
container.Register<IOpenable>( c => c.ResolveShared<IDoor>(); );
container.Register<ICloseable>( c => c.ResolveShared<IDoor>(); );

如果在同一构造函数中调用多个参数,则其中对c.ResolveShared<T>的调用将全部解析为同一个T对象.

where calls to c.ResolveShared<T> will all resolve to the same T object if called for more than one argument in same constructor.

或者也许:

container.RegisterType<DoorHandler>().As<IDoorHandler>();
container.RegisterType<Door>().As<IDoor>().InstancePerDependencyShared();
container.Register<IOpenable>( c => c.Resolve<IDoor>(); );
container.Register<ICloseable>( c => c.Resolve<IDoor>(); );

很显然,如果我对Instance对象使用InstancePerLifetimeScope或其他东西,则每个解析的Door都将是同一实例.但是我不希望这样,每次创建DoorHandler时都想要一个新的Door实例,并且希望将该Door作为两个参数都传递给DoorHandler构造函数.

Obviously if I was using an InstancePerLifetimeScope or something for the Door object, each resolved Door would be the same instance. But I don't want that, I want a new instance of Door each time a DoorHandler is created, and I want that Door to be passed as both arguments to the DoorHandler constructor.

推荐答案

好棘手的一个:) ...这是广义的每个构造函数"共享的一种可能的解决方案:

Ok tricky one :) ... Here's one possible solution for generalised "per constructor" sharing:

builder.RegisterControllers(asm)        
    .OnPreparing(e => {
        var spr = new SharedConstructorParameter(
            typeof(IOpenable),
            typeof(ICloseable));
        e.Parameters = new Parameter[]{ spr }.Concat(e.Parameters);
    });

需要在OnPreparing()事件中设置参数,因为SharedConstructorParameter实例将是每个解析操作的值的缓存.

The parameter needs to be set up in the OnPreparing() event because the SharedConstructorParameter instance will be the cache of values per resolve operation.

class SharedConstructorParameter : Parameter
{
    object _cachedInstance;
    Type[] _sharedParameterTypes;

    public SharedConstructorParameter(params Type[] sharedParameterTypes)
    {
        _sharedParameterTypes = sharedParameterTypes;
    }

    protected override bool CanSupplyValue(
        ParameterInfo pi,
        IComponentContext cc,
        out Func<object> valueCreator)
    {
        valueCreator = null;
        if (!_sharedParameterTypes.Contains(pi.ParameterType))
            return false;

         valueCreator = () => {
             _cachedInstance = _cachedInstance ?? cc.Resolve(pi.ParameterType);
             return cachedInstance;
         };
         return true;
    }
}

您要编译和调试;)

这篇关于如何使用Autofac注入同一对象的两个实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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