使用Unity进行属性依赖注入的正确方法

时间:2014-04-04 10:45:48

标签: c# dependency-injection unity-container ioc-container

我有一个需要依赖注入的类。由于该类已经是另一个抽象的实现,并且它的“兄弟”实现可能不共享相同的依赖项,我试图使用属性注入而不是构造函数注入。

(所有这些类/接口名称仅用于说明目的)

我的 IProvider 抽象:

public interface IProvider
{
    void ProviderMethod();
}

我的 IProvider 实现(我要注入的IData依赖项)

public class ProviderClass : IProvider
{
    // How do I inject this dependency?
    [Dependency]
    public IData data { get; set; }

    public void ProviderMethod()
    {
        // Can't do this as data == null!
        data.DataMethod();
    }
}

另一个 IProvider 实现(示例表明它没有相同的依赖项):

public class AnotherProviderClass : IProvider
{
    // No data dependency here!!

    public void ProviderMethod()
    {
        // Do other stuff here
    }
}

示例 IData 抽象和实现:

public interface IData
{
    void DataMethod();
}

public class DataClass : IData
{
    public void DataMethod();
}

我需要知道的是:如何使用Unity(我选择的IOC容器)将属性依赖项( IData )成功注入 ProviderClass

我已尝试过各种Unity注册选项(RegisterType,RegisterInstance,Resolve ...),但我的注入属性总是以NULL结尾。我想要做到这一点,而不仅仅是强制使用随机代码,直到它成功运行。

或者是否有更好的方法将(可选的)依赖项注入“兄弟”类?

顺便提一下,我的初始IProvider实现是通过抽象工厂创建的,所以也许这可能是我应该把这个IData依赖关注的另一个领域(?)

1 个答案:

答案 0 :(得分:4)

你仍然应该使用构造函数注入,因为dependencies should hardly ever be optional

您正试图在IProviderFactory实施中阻止constructor over-injection,并且您可能不希望将容器注入工厂以防止落入Service Locator anti-pattern

但是,如果您在Composition Root内定义了IProviderFactory实施,那么即使您注入容器,也会阻止自己执行服务定位器,因为Service Locator is not about mechanics

因此,您应该将ProviderFactory实现定义为尽可能接近Unity配置,它应该如下所示:

public class ProviderFactory : IProviderFactory
{
    private readonly Dictionary<string, Type> providerTypes;
    private readonly Container container;

    public ProviderFactory(Dictionary<string, Type> providerTypes, 
        Container container) {
        this.providerTypes = providerTypes;
        this.container = container;
    }

    public IProvider CreateProvider(string name) {
        return (IProvider)this.container.Resolve(this.providerTypes[name]);
    }
}

此实现可以在Unity中注册为singleton。这使您无需在工厂中进行构造函数过度注入,同时远离服务定位器。