温莎城堡充满争议的生活方式

本文关键字:生活方式 满争议 城堡 | 更新日期: 2023-09-27 18:24:59

我让我的IoC容器管理我的对象图的生命,并且似乎在重用一种特定的生活方式,而这种生活方式目前在Castle Windsor默认设置中是不可用的。

示例

我需要通过将解析时间参数传递到工厂来构建对象上下文,例如,当我传递字符串Dorothy时,如果容器中还不存在Person的单例,或者现有的Dorothy实例,我希望返回一个将用字符串Doroth实例化的Person的实例。将字符串参数Jane传递到我的工厂时也是如此-请返回Person Jane的singleton。可能还有Sally、Bob和许多其他人,完整的输入集仅在运行时分解。

手动执行

下面是另一个例子,在我的自定义类中使用字典实现:

private readonly static IDictionary<string,IRecruiter> Recruiters
                        = new Dictionary<string, IRecruiter>();
private IRecruiter GetRecruiter(string recruiterId)
    {
    IRecruiter recruiter;
    if (!Recruiters.TryGetValue(recruiterId, out recruiter))
                    {
                    recruiter = this.donorFactory.CreateRecruiter(recruiterId);
                    Recruiters.Add(recruiterId,recruiter);
                    }
    return recruiter;
    }

donorFactory CreateRecruiter方法的作用如下:

return this.Create<IRecruiter>(new Arguments { { typeof(string), recruiterId }});

SRP和还原沸腾板

我发现我经常使用这种模式,所以我想知道是否有可能使用现有的温莎城堡生活方式,或者是否有理由将这种模式添加到温莎城堡本身?

  • 在这种情况下,将组件注册为.Named不起作用,因为传入参数集在设计时未知
  • 如果使用GetHashCode或类似的东西作为字典的键,那么该模式可以有一个通用的实现,它可以处理任何类型的参数(而不仅仅是字符串),甚至可以处理参数集

温莎城堡充满争议的生活方式

我可以通过创建自定义作用域访问器来找到一种方法:

public class ArgScopeAccessor : IScopeAccessor
{
    static readonly ConcurrentDictionary<string, ILifetimeScope> collection = new ConcurrentDictionary<string, ILifetimeScope>();
    public void Dispose()
    {
        foreach (var scope in collection)
            scope.Value.Dispose();
        collection.Clear();
    }
    public ILifetimeScope GetScope(CreationContext context)
    {
        string name = (string)context.AdditionalArguments["name"];
        return collection.GetOrAdd(name, n => new DefaultLifetimeScope());
    }
}

这将基于传递到解析对象的调用中的name参数创建一个作用域。然后,我会使用类型化的工厂设施来创建一个IRecruiterFactory(带有一个名为name的参数):

public interface IRecruiterFactory
{
    IRecruiter Create(string name);
}

假设你的IRecruiterRecruiter是这样的:

public interface IRecruiter
{
    string Name { get; }
}
public class Recruiter : IRecruiter
{
    public Recruiter(string name)
    {
        Name = name;
    }
    public string Name { get; private set; }
}

然后你可以设置你的容器,以这样一种可重复使用的方式使用这个范围:

container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IRecruiterFactory>()
                            .AsFactory());
container.Register(Component.For<IRecruiter>()
                            .ImplementedBy<Recruiter>()
                            .LifestyleScoped<ArgScopeAccessor>());

因此,现在,通过名称解析招聘人员将解析相同的实例:

IRecruiterFactory recruiterFactory = container.Resolve<IRecruiterFactory>();
IRecruiter jane1 = recruiterFactory.Create("Jane");
IRecruiter susan = recruiterFactory.Create("Susan");
IRecruiter jane2 = recruiterFactory.Create("Jane");
Console.WriteLine("Jane 1: " + jane1.GetHashCode());
Console.WriteLine("Jane 2: " + jane2.GetHashCode());
Console.WriteLine("Susan:  " + susan.GetHashCode());

显示器:

简1:60467532简2:60467532苏珊:63249743

显然,您可以创建一个不同的作用域访问器来处理您想要区分类型的任何其他方式,例如哈希代码或参数组合。但是,我看不到更改ArgScopeAccessorname常量的方法,因为在容器上配置作用域访问器时,无法传入构造函数参数。但这可以通过基类型和仅指定常量的派生类型来解决。