参数化实例化如何与单实例生命周期范围配合使用



根据参数化实例化(Func<X, Y, B>)文档:

但是,如果将对象注册为 SingleInstance() 并调用 Func<X、Y、B> 来多次解析对象,则每次都会获得相同的对象实例,而不管您传入的不同参数如何。仅传递不同的参数不会破坏对生存期范围的尊重。

具有不同参数构造函数的单一实例类如何工作?

Autofac 工厂注册不会缓存每个参数的实例。

让我们尝试使用以下类型:

public class Foo
{
    public Foo(Int32 a)
    {
        this._a = a;
    }
    private readonly Int32 _a;
    public override String ToString()
    {
        return String.Format("a={0}", this._a);
    }
}

如果您像这样注册:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Foo>().AsSelf().SingleInstance();

Autofac 将全部注册单个实例,无论您如何解析它(即使您使用Func工厂):

Func<Int32, Foo> foo1Factory = scope.Resolve<Func<Int32, Foo>>();
Foo foo1 = foo1Factory(1);
Func<Int32, Foo> foo2Factory = scope.Resolve<Func<Int32, Foo>>();
Foo foo2 = foo2Factory(2);

foo1foo2将是同一个实例。

如果希望每个参数只有一个实例,这意味着您需要多个Foo实例,因此无法使用 SingleInstance() 方法注册Foo。您必须实现一个自定义工厂,该工厂将执行缓存,以便每个参数有一个实例:

public class FooFactory
{
    public FooFactory(IComponentContext componentContext)
    {
        this._componentContext = componentContext;
        this._instances = new Dictionary<Int32, Foo>();
        this._lock = new Object();
    }
    private readonly IComponentContext _componentContext;
    private readonly Dictionary<Int32, Foo> _instances;
    private readonly Object _lock;
    public Foo GetInstance(Int32 a)
    {
        Foo parameterizedFoo;
        if (!this._instances.TryGetValue(a, out parameterizedFoo))
        {
            lock (this._lock)
            {
                if (!this._instances.TryGetValue(a, out parameterizedFoo))
                {
                    Parameter aParameter = new TypedParameter(typeof(Int32), a);
                    parameterizedFoo = this._componentContext
                                           .Resolve<Foo>(aParameter);
                    this._instances[a] = parameterizedFoo;
                }
            }
        }
        return parameterizedFoo;
    }
}

您可以通过以下方式注册它:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Foo>().AsSelf();
builder.RegisterType<FooFactory>().AsSelf().SingleInstance();

使用以下代码来使用它:

FooFactory fooFactory = scope.Resolve<FooFactory>();
Foo foo = fooFactory.GetInstance(1);

但是如果你想使用 Func<Int32, Foo> 而不是 FooFactory.GetInstance ,你可以将该方法注册为 Func<Int32, Foo>

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Foo>().AsSelf();
builder.RegisterType<FooFactory>().AsSelf().SingleInstance();
builder.Register(c => new Func<Int32, Foo>(c.Resolve<FooFactory>().GetInstance))
       .As<Func<Int32, Foo>>()
       .SingleInstance();

您现在可以使用此代码:

Func<Int32, Foo> foo1Factory = scope.Resolve<Func<Int32, Foo>>();
Foo foo1 = foo1Factory(1);
Func<Int32, Foo> foo2Factory = scope.Resolve<Func<Int32, Foo>>();
Foo foo2 = foo2Factory(2);
Func<Int32, Foo> foo1PrimeFactory = scope.Resolve<Func<Int32, Foo>>();
Foo foo1Prime = foo1PrimeFactory(1);

foo1foo2会有所不同,而foo1Prime将与foo1相同。

最后,我的同事也有类似的方法

public interface IKey
{
}
public interface IKeyed<out T>
{
    T this[IKey key] { get; }
}
public class Keyed<T> : IKeyed<T>
{
    private ConcurrentDictionary<IKey, T> _dict = new ConcurrentDictionary<IKey,T>();
    T IKeyed<T>.this[IKey key]
    {
        get 
        {
            return _dict.GetOrAdd(key, k => IoC.Resolve<T>(new TypedParameter(key.GetType(), key)));
        }
    }
}

在应用开始中,注册

   _builder.RegisterGeneric(typeof(Keyed<>))
        .As(typeof(IKeyed<>))
        .SingleInstance();

最新更新