首页 > 解决方案 > 使用 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#dependency-injectionunity-container

解决方案


工厂模式是一种基于其他依赖关系或逻辑选择构造对象的方式。

工厂方法:“定义一个用于创建对象的接口,但让实现该接口的类决定实例化哪个类。工厂方法让一个类将实例化推迟到子类”(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 不必使用接口,它可以是一个具体的实现。存储库上的接口是一个很好的用途,因为您可以轻松地将数据库切换出来,但实际上并不需要像这样的工厂接口。


推荐阅读