c# - 使用 Unity C# 将父级注入复合构造函数
问题描述
我试图让 IoC 在 C# 中与 Unity 一起工作,并将包装器/复合类传递给子级。
组成多个类的顶级类提供了组合类需要访问的一些通用功能。
为了显示:
// The top composite class
public class Context : IContext {
public ISomething SomethingProcessor { get; }
public IAnother AnotherProcessor { get; }
public Context(ISomething something, IAnother another) {
this.SomethingProcessor = something;
this.AnotherProcessor = processor;
}
// A function that individual classes need access to, which itself calls one of the children.
public string GetCommonData() {
return this.AnotherProcessor.GetMyData();
}
}
public class Something : ISomething {
private _wrapper;
public Something(IContext context) {
this._wrapper = context;
}
// This class has no knowledge of IAnother, and requests data from the master/top class, which knows where to look for whatever.
public void Do() {
Console.WriteLine(_wrapper.GetCommonData());
}
}
public class Another : IAnother {
public string GetMyData() {
return "Foo";
}
}
如果你不使用 IoC,这很容易,因为 Context 类的构造函数变为:
public Context() {
this.SomethingProcessor = new Processor(this);
this.AnotherProcessor = new Another();
}
但是当你使用 IoC 时,“this”的概念还不存在,因为它还没有被注入器构造。相反,您拥有的是循环依赖。
container.RegisterType<ISomething, Something>();
container.RegisterType<IAnother, Another>();
container.RegisterType<IContext, Context>();
var cxt = container.Resolve<IContext>(); // StackOverflowException
上面的例子已经大大简化以说明这个概念。我正在努力寻找处理这种结构以启用 IOC 的“最佳实践”方式。
解决方案
工厂模式是一种基于其他依赖关系或逻辑选择构造对象的方式。
工厂方法:“定义一个用于创建对象的接口,但让实现该接口的类决定实例化哪个类。工厂方法让一个类将实例化推迟到子类”(c)GoF。
大量的建设..因此名称工厂模式
可与 DI 一起使用的粗略代码示例
public class ContextFactory : IContextFactory {
_anotherProcessor = anotherProcessor;
public ContextFactory(IAnotherProcessor anotherProcessor) {
//you can leverage DI here to get dependancies
}
public IContext Create(){
Context factoryCreatedContext = new Context();
factoryCreatedContext.SomethingProcessor = new SomethingProcessor(factoryCreatedContext )
factoryCreatedContext.AnotherProcessor = _anotherProcessor;
//You can even decide here to use other implementation based on some dependencies. Useful for things like feature flags.. etc.
return context;
}
}
你可以摆脱这个,也许?- 但这里仍然存在循环引用问题,我永远不会提交这种代码。
这里的问题你需要专注于控制反转GetCommonData
你SomethingProcessor
不应该依赖另一个类中的方法。这是可以使用 In Inheritance 的地方,但 Inheritance 很快就会变得非常复杂。
最好的方法是确定两个或许多其他地方都需要的一个东西,并将其分解为一个新的依赖关系。这就是您反转控制的方式。
小费:
不要过度使用接口 - 在您认为将使用多态性的地方使用接口,例如必须向您保证它们已经实现特定方法/属性的不同对象的集合。否则,您将过度使用接口并增加复杂性。DI 不必使用接口,它可以是一个具体的实现。存储库上的接口是一个很好的用途,因为您可以轻松地将数据库切换出来,但实际上并不需要像这样的工厂接口。