Unity:通过构造函数依赖关系解析接口实现

时间:2016-02-29 21:44:21

标签: c# inversion-of-control unity-container

我正在尝试了解IoC并确定它是否适合这种特定情况。我有以下代码:

public class List { ... }
public class Form { ... }

public interface IService { ... }

public class ListService : IService {
    public ListService(List list) { }
}

public class FormService : IService {
    public FormService(Form form) { }
}

class Program {
    static void Main(string[] args) {
        IUnityContainer container = new UnityContainer();
        container.RegisterType<IService, ListService>(new InjectionConstructor(typeof(List)));
        container.RegisterType<IService, FormService>(new InjectionConstructor(typeof(Form)));

        IService formService = container.Resolve<IService>(new DependencyOverride<Form>(new Form()));
        IService listService = container.Resolve<IService>(new DependencyOverride<List>(new List()));
    }
}

上面的代码显然不起作用,因为IService的第二次注册会覆盖第一个。但目的是能够使用其构造函数依赖项来解析正确的IService实例。我意识到这不是典型的IoC场景,而是混合工厂/ IoC,我想知道是否可以连接统一以适应这种情况。

编辑结论:
实际问题比上面的例子更复杂。 ServiceDefinition对象(List,Form)来自WCF Web服务。从那里,系统将构造IService实例和一系列其他对象,最终导致一组WPF视图和视图模型。一些依赖项在构造函数中明确定义,其他依赖项使用接口作为构造函数参数。

我的第一种方法是使用命名注册与InjectionConstructor \ ResolvedParameter结合使用。但它很快变得非常复杂。根据Randy的建议,我开始使用Unity调查汽车工厂。这是关于该技术的related post。这是我生成的代码片段

public class Form { }
public class FormService : IService{
    [InjectionConstructor]
    public FormService(Func<string, Form> func, string name):this(func(name)) { }
    public FormService(Form form) { }
}
public class FormDataViewModel {
    public FormDataViewModel(FormService svc) { }
}
public interface IService { }
class Program {
    static Form GetForm(string name) {
        //wcf call
        return new Form();
    }
    static void Main(string[] args) {
        IUnityContainer container = new UnityContainer();
        container.RegisterInstance<Func<string, Form>>(GetForm);
        container.RegisterType<IService, FormService>("form");
        FormDataViewModel vm = container.Resolve<FormDataViewModel>(new DependencyOverride<string>("/system/form/test"));
    }
}

上面的代码在某种意义上是混合工厂\ IoC方法。感谢Unity的灵活性。纯IoC在我的许多场景中都不适用。

1 个答案:

答案 0 :(得分:2)

使用Unity,只有一个与接口相关联的注册的唯一方法(开箱即用)是使用命名注册。

在您呈现的场景中(实际场景可能更复杂),它似乎不应该是一个问题。我想你会以某种方式知道你想要什么类型的服务(Form vs. List)。

如果场景更复杂,那么你几乎总能达到你想要的工厂(工厂在问题中提到它似乎适合)。有关工厂示例,请参阅Automatic Factories

基本上,IService的所有适用实例都可以注入工厂,工厂可以在运行时(并根据适用的标准)确定要返回的适当IService实例。您甚至可以注入Func<IService>而不是IService来推迟创建对象。