找到你要的答案

Q:how Parameterized Instantiation work with SingleInstance lifescope

Q:多参数实例化与SingleInstance lifescope合作

In Parameterized Instantiation (Func<X, Y, B>) documentation, last sentence said

However, if you register an object as SingleInstance() and call the Func 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.

How it works a singleton class with different parameter constructor.

在参数实例化(功能<;X,Y,B & gt;)文件,最后一句说

然而,如果你登记一个对象作为singleinstance()调用函数来解决对象不止一次,你每次都会不同的参数传递到同一个对象实例。仅仅传递不同的参数不会破坏对生命周期范围的尊重。

如何使用具有不同参数构造函数的单例类。

answer1: 回答1:

Autofac factory registration won't cache instance per parameters.

Let's have a try, imagine the following type :

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);
    }
}

if you register it like this :

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

Autofac will allways register a single. No matter how you resolve it (event if you use func factory).

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 and foo2 will be the same instance.

If you want to have only 1 instance per parameter, it means that you want more than a single instance of Foo, so you can't register Foo using SingleInstance() method. You will have to implement a custom factory that will do caching to have 1 instance per parameter.

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;
    }
}

You can register it this way :

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

Use the following code to use it :

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

But if you don't want to use FooFactory.GetInstance instead of Func<Int32, Foo>, you can register the method as 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();

You now can use this code

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 and foo2 will be different whereas foo1Prime will be same as foo1.

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<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将相同的实例。

如果你想每个参数仅1例,这意味着你要比富的一个实例,所以你不能登记使用singleinstance() foo方法。你将不得不实现一个自定义的工厂,它将做缓存每个参数有1个实例。

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);

但如果你不想使用foofactory.getinstance代替功能& lt;Int32,foo & gt;,你可以登记方法func <;Int32,foo & gt;

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。

answer2: 回答2:

finally, my workmate has a similar approach

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)));
        }
    }
}

and in app start, register

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

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

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();
c#  autofac