参数化实例化如何与单实例生命范围一起工作

How Does Parameterized Instantiation Work with SingleInstance Life Scope

根据 Parameterized Instantiation (Func<X, Y, B>) 文档:

However, if you register an object as SingleInstance() and call the Func<X, Y, B> to resolve the object more than once, you will get the same object instance every time regardless of the different parameters you pass in. Just passing different parameters will not break the respect for the lifetime scope.

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

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 的多个实例,所以你不能使用 [=23= 注册 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();