使用 Unity C# 将父项注入复合构造函数
Injecting parents into composite constructors with Unity C#
我正在尝试让 IoC 在 C# 中与 Unity 一起工作,并希望将 wrapper/composite class 传递给子项。
组成多个 classes 的顶级 class 提供了组成的 classes 需要访问的一些通用功能。
举例说明:
// 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 class 的构造函数变为:
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>(); // WhosebugException
上面的例子已经被大大简化以说明这个概念。我正在努力寻找 "best practice" 处理这种结构以启用 IOC 的方法。
我不知道这个模式的名称,也不知道它是好是坏,但是您可以通过创建一个绑定 [=35= 的方法来解决 "double-binding" 的问题],而不是在构造函数中进行。
例如,
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" 使事情变得更精彩 "DRY"(不要重复自己)并使 IAnother
和 ISomething
继承它。
未测试,再次:不确定这是进行此类依赖关系设计的最佳方式。如果有另一个答案可以提供最先进的见解,我会很高兴。
工厂模式是一种基于其他依赖项或逻辑选择构造对象的方法。
Factory Method: "Define an interface for creating an object, but let
the classes which implement the interface decide which class to
instantiate. The Factory method lets a class defer instantiation to
subclasses" (c) GoF.
Lots of construction.. hence the name 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;
}
}
你可以摆脱这个,也许吧? - 但这里仍然存在循环引用问题,我永远不会提交这种代码。
这里的问题你需要专注于Inversion Of Control GetCommonData
您的 SomethingProcessor
不应依赖另一个 class 中的方法。这是可以使用 In Inheritance 的地方,但是 Inheritance 很快就会变得非常复杂。
最好的方法是确定两个或许多其他地方都需要的一件事,并将其分解为一个新的依赖项。这就是您反转控制的方式。
提示:
不要过度使用接口 - 在您认为将使用多态性的地方使用接口,例如必须向您保证它们已实现特定 method/property 的不同对象的集合。否则,您将过度使用接口并增加复杂性。 DI 不必使用接口,它可以是具体的实现。存储库上的接口很有用,因为您可以轻松切换数据库,但实际上并不需要像这样的工厂接口。
我正在尝试让 IoC 在 C# 中与 Unity 一起工作,并希望将 wrapper/composite class 传递给子项。
组成多个 classes 的顶级 class 提供了组成的 classes 需要访问的一些通用功能。
举例说明:
// 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 class 的构造函数变为:
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>(); // WhosebugException
上面的例子已经被大大简化以说明这个概念。我正在努力寻找 "best practice" 处理这种结构以启用 IOC 的方法。
我不知道这个模式的名称,也不知道它是好是坏,但是您可以通过创建一个绑定 [=35= 的方法来解决 "double-binding" 的问题],而不是在构造函数中进行。
例如,
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" 使事情变得更精彩 "DRY"(不要重复自己)并使 IAnother
和 ISomething
继承它。
未测试,再次:不确定这是进行此类依赖关系设计的最佳方式。如果有另一个答案可以提供最先进的见解,我会很高兴。
工厂模式是一种基于其他依赖项或逻辑选择构造对象的方法。
Factory Method: "Define an interface for creating an object, but let the classes which implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses" (c) GoF.
Lots of construction.. hence the name 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;
}
}
你可以摆脱这个,也许吧? - 但这里仍然存在循环引用问题,我永远不会提交这种代码。
这里的问题你需要专注于Inversion Of Control GetCommonData
您的 SomethingProcessor
不应依赖另一个 class 中的方法。这是可以使用 In Inheritance 的地方,但是 Inheritance 很快就会变得非常复杂。
最好的方法是确定两个或许多其他地方都需要的一件事,并将其分解为一个新的依赖项。这就是您反转控制的方式。
提示:
不要过度使用接口 - 在您认为将使用多态性的地方使用接口,例如必须向您保证它们已实现特定 method/property 的不同对象的集合。否则,您将过度使用接口并增加复杂性。 DI 不必使用接口,它可以是具体的实现。存储库上的接口很有用,因为您可以轻松切换数据库,但实际上并不需要像这样的工厂接口。