如何构造函数 - 注入仅在运行时已知的字符串? (温莎城堡)

时间:2014-12-16 14:53:16

标签: c# .net dependency-injection inversion-of-control castle-windsor

我的类依赖于string:

public class Person
{
    private readonly string _name;

    public Person(string name)
    {
        if (name == null) throw new ArgumentNullException("name");
        _name = name;
    }
}

此字符串'name'仅在运行时知道,例如。它在配置中定义。所以我有这个提供这个字符串的接口:

public interface IConfiguration
{
    string Name { get; }
}

两种类型,Person和IConfiguration(其实现在这里并不重要)都在Windsor容器中注册。

问题:如何告诉WindsorCastle容器它应该将IConfiguration的Name属性注入Person类的构造函数?

警告:我不想将IConfiguration注入Person类或使用类型化工厂...... Person类必须简单并且只接受字符串作为参数。

1 个答案:

答案 0 :(得分:5)

可能有更多的方法可以做到这一点,因为温莎是非常灵活的,但这里有三个我的头顶:

选项1:

如果IConfiguration是单身人士,或者在没有任何其他帮助的情况下以某种方式填充Name,您可以执行以下操作:

container.Register(Component.For<IConfiguration>().ImplementedBy<Configuration>());
container.Register(Component
    .For<Person>()
    .DynamicParameters((DynamicParametersDelegate)ResolvePersonName));

// This should be a private method in your bootstrapper 
void ResolvePersonName(IKernel kernel, IDictionary parameters)
{
    parameters["name"] = kernel.Resolve<IConfiguration>().Name;
}

在解析Person之前调用此方法,并将name键/值对设置为所需的值。然后,Windsor使用此字典覆盖构造函数中的任何依赖项。我可能只是把它变成了一个更为简洁的lambda:

    .DynamicParameters((k,p) => p["name"] = k.Resolve<IConfiguration>().Name));

选项2:

如果在应用程序设置文件中实际定义了Name值,Windsor有一个内置选项:

container.Register(
    Component.For<Person>()
    .DependsOn(Dependency.OnAppSettingsValue("name", "configSettingKeyName")));

选项3:

你说你不想使用Typed Factories,但我认为这是一个合理的使用方法。它根本不会使Person类复杂化,但它会为创建Person对象的代码(人?)添加一些内容。这是一个例子:

定义工厂界面:

public interface IPersonFactory
{
    Person Create(string name);
}

然后在创建Person的地方,注入工厂并改为使用它:

public class PersonUser
{
    public Personuser(IConfiguration configuration, IPersonFactory personFactory)
    {
        Person person = personFactory.Create(configuration.Name);
    }
}

您必须添加设施并注册界面,但这很简单:

container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IPersonFactory>().AsFactory());