每个构造函数参数缓存实例

时间:2015-09-28 07:31:16

标签: c# dependency-injection autofac

我有PlayerCharacterSpawner,其构造函数中包含IPlayer

    class CharacterSpawner : ICharacterSpawner
    {
        public CharacterSpawner(IPlayer player, SomeDep dep)
        {
            // ...
        }

        public void SpawnNext()
        {
            // ...
        }
    }

在我的应用的某些部分,我想针对特定ICharacterSpawner解析IPlayer。我想缓存ICharacterSpawner个实例,以便每个IPlayer只创建一个实例。我怎么能用Autofac做到这一点?

更新 建议的现有答案不是关于AutoFac,而是关于Castle。我需要在项目中使用Autofac。

1 个答案:

答案 0 :(得分:1)

Autofac中没有内置支持可以满足您的需求,但我可以通过注册lambda表达式来查看解决方案,该表达式将从ICharacterSpawner中选择Dictionary。关键是将提供的上下文转换为IInstanceLookup以检索提供的IPlayer

以下是适用于您的案例的示例代码。我使用IServiceIOwner定义为:

interface IService
{
    String Code { get; }
}
class MyService : IService
{
    public MyService() : this(DateTime.Now.Ticks.ToString())
    { }
    public MyService(String code)
    {
        this.Code = code;
    }
    public String Code { get; }
}

interface IOwner { }
class Owner : IOwner
{
    public Owner(IService service)
    {
        Console.WriteLine($"new owner for service {service.Code}");
    }
}

我的注册如下:

ContainerBuilder builder = new ContainerBuilder();
var owners = new ConcurrentDictionary<IService, IOwner>();
builder.RegisterType<MyService>().As<IService>().OnRelease(o =>
{
    IOwner owner;
    owners.TryRemove(o, out owner);
});
builder.RegisterType<Owner>().Named<IOwner>("newOwner");
builder.Register(c =>
{
    IEnumerable<Parameter> parameters = Enumerable.Empty<Parameter>();
    IInstanceLookup instanceLookup = c as IInstanceLookup;
    if (instanceLookup != null)
    {
        parameters = instanceLookup.Parameters;
    }

    IService service = parameters.OfType<TypedParameter>()
                                 .Where(tp => tp.Type == typeof(IService))
                                 .Select(tp => tp.Value)
                                 .OfType<IService>()
                                 .FirstOrDefault();
    if (service == null)
    {
        service = c.Resolve<IService>();
        parameters = parameters.Concat(new Parameter[] {
            TypedParameter.From<IService>(service)
        });
    }

    IOwner owner = owners.GetOrAdd(service, _ =>
        c.ResolveNamed<IOwner>("newOwner", parameters)
    );

    return owner;
}).As<IOwner>();

IContainer container = builder.Build();

然后你就可以做到了

IService service1 = new MyService("service1");
IService service2 = new MyService("service2");

container.Resolve<IOwner>(TypedParameter.From<IService>(service1));
container.Resolve<IOwner>(TypedParameter.From<IService>(service1));
container.Resolve<IOwner>(TypedParameter.From<IService>(service2));