根据参数化实例化(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);
foo1
和foo2
将是同一个实例。
如果希望每个参数只有一个实例,这意味着您需要多个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);
foo1
和foo2
会有所不同,而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();