简体   繁体   English

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

[英]How to constructor-inject a string that is only known at runtime? (Windsor Castle)

I have class that has dependency on string: 我有一个依赖于字符串的类:

public class Person
{
    private readonly string _name;

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

This string 'name' is known only at runtime, eg. 该字符串'name'仅在运行时才知道,例如。 it is defined in configuration. 它在配置中定义。 So I have this interface that provides this string: 所以我有这个提供这个字符串的接口:

public interface IConfiguration
{
    string Name { get; }
}

Both types, Person and IConfiguration (with its implementation which is not important here) are registered with Windsor container. 这两种类型,Person和IConfiguration(其实现在这里并不重要)都在Windsor容器中注册。

Question: how can I tell WindsorCastle container that it should inject the Name property of IConfiguration to the constructor of Person class? 问题:如何告诉WindsorCastle容器它应该将IConfiguration的Name属性注入Person类的构造函数?

Caveat: I don't want to inject IConfiguration to Person class or use typed factories... the Person class must be simple and accept only string as parameter. 警告:我不想将IConfiguration注入Person类或使用类型化的工厂...... Person类必须简单并且只接受字符串作为参数。

There are probably more ways to do this since Windsor is ridiculously flexible, but here are three off the top of my head: 可能有更多的方法可以做到这一点,因为温莎是非常灵活的,但这里有三个我的头顶:

Option 1: 选项1:

If IConfiguration is a singleton or somehow can populate Name without any other assistance, you could do the following: 如果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;
}

This method is invoked before resolving the Person , and is setting the name key/value pair to be the desired value. 在解析Person之前调用此方法,并将name键/值对设置为所需的值。 Windsor then uses this dictionary to override any dependencies in the constructor. 然后,Windsor使用此字典覆盖构造函数中的任何依赖项。 I'd probably just make it a lambda to be terser: 我可能只是让它成为一个lambda:

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

Option 2: 选项2:

If the Name value is actually defined in the applications settings file, Windsor has a built-in option for that: 如果Name值实际上是在应用程序设置文件中定义的,那么Windsor有一个内置选项:

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

Option 3: 选项3:

You say you don't want to use Typed Factories , but I think this is a reasonable siutation for using one. 你说你不想使用Typed Factories ,但我认为这是一个合理的使用方法。 It wouldn't complicate the Person class at all, but it would add a bit to the code creating the Person objects (people?). 它根本不会使Person类复杂化,但它会为创建Person对象的代码添加一些内容(人?)。 Here's an example: 这是一个例子:

Define the factory interface: 定义工厂界面:

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

Then where you are creating your Person , inject the factory and use that instead: 然后在您创建Person ,注入工厂并使用它:

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

You'll have to add the facility and register the interface, but it's easy: 您必须添加设施并注册界面,但这很容易:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM