使用Unity C#将父母注入复合构造函数

时间:2019-01-30 12:25:31

标签: c# dependency-injection unity-container

我试图让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的“最佳实践”方法。

2 个答案:

答案 0 :(得分:2)

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

  

工厂方法:“定义用于创建对象的接口,但让   实现该接口的类决定要哪个类   实例化。 Factory方法允许类将实例化延迟到   子类”(c)GoF。

     

很多建筑,因此得名Factory Pattern

可以与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不必使用接口,它可以是一个具体的实现。存储库上的接口很好用,因为您可以轻松地切换数据库,但是实际上不需要像这样的工厂接口。

答案 1 :(得分:1)

我不知道此模式的名称,即使它是不好的做法,也可以,但是您可以通过创建一个绑定“ IContext”的方法来解决“双重绑定”的问题,而不是在构造函数中完成。

例如

1)ISomething有一种void BindContext(IContext context)方法

2)您可以这样实现:

class Something : ISomething 
{
   IContext _wrapper;

   // ... nothing in constructor

   public void BindContext(IContext context)
   {
        _wrapper = context;
   }
}

3)在Something构造函数中删除IContext依赖项注入。

然后从上下文构造函数中调用它:

public Context(ISomething something, IAnother another) {
    this.SomethingProcessor = something;
    this.SomethingProcessor.BindContext(this);

    // same for IAnother
}

您对IAnother执行相同的操作。您甚至可以提取一些通用接口“ IBindContext”,使事情变得更“干”(不要重复自己),并使IAnotherISomething继承自它。

未经测试,再说一遍:不确定这是进行此类依赖项设计的最佳方法。如果有另一个答案可以对此提供最新的见解,我会感到很高兴。