Ric*_*ard 5 c# oop events dependency-injection
我一直在努力重构一个应用程序,以便通过依赖注入和所有好东西使其更易于管理.这样做时,我不止一次遇到过循环依赖.
所以这是循环依赖的典型示例:
interface IA
{
int Data { get; }
}
interface IBefore
{
void DoStuffBefore();
}
class A: IA
{
public int Data { get; private set; }
IBefore before;
public A(IBefore before)
{
this.before = before;
}
public void Increment()
{
before.DoStuffBefore();
Data++;
}
}
class B: IBefore
{
IA a;
public B(IA a)
{
this.a = a;
}
public void WriteADataToConsole()
{
Console.Write(a.Data);
}
public void DoStuffBefore() //From IBefore
{
WriteADataToConsole();
}
}
Run Code Online (Sandbox Code Playgroud)
我不能创建任何类,因为它们需要彼此.现在,在这种情况下要做的标准(?)事情是将A的数据与A分开:
public interface IA
{
int Data { get; set; }
}
public interface IBefore
{
void DoStuffBefore();
}
class AData : IA
{
public int Data { get; set; }
}
class A
{
public IA Data { get; private set; }
IBefore before;
public A(IA data, IBefore before)
{
this.Data = data;
this.before = before;
}
public void Increment()
{
before.DoStuffBefore();
Data.Data++;
}
}
class B : IBefore
{
IA a;
public B(IA a)
{
this.a = a;
}
public void WriteADataToConsole()
{
Console.Write(a.Data);
}
public void DoStuffBefore() //From IBefore
{
WriteADataToConsole();
}
}
Run Code Online (Sandbox Code Playgroud)
上面解决了循环依赖,因为我现在可以先创建AData,然后将其注入B并将B注入A.但我也可以放一个B可以监听的事件:
public interface IA
{
int Data { get; }
event Action BeforeEvent;
}
class A: IA
{
public int Data { get; private set; }
public event Action BeforeEvent;
public void Increment()
{
BeforeEvent();
Data++;
}
}
class B
{
IA a;
public B(IA a)
{
this.a = a;
a.BeforeEvent += new Action(WriteADataToConsole);
}
void WriteADataToConsole() //Event listener
{
Console.Write(a.Data);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我偶然发现的声音,因为我试图将事件方法转换为依赖注入,并意识到通过这样做我已经得到了循环依赖.
一些困扰我大脑的问题是:
好问题!在 95% 的情况下,您必须将这两个实体合并在一起或以其他方式打破依赖关系,但是\xe2\x80\xa6 如果由于某种原因或其他原因无法将它们合并到一个实体中怎么办(使用 UI有时可能会很棘手)?Mark Seemann写了一本关于“.NET 中的依赖注入”的书,其中描述了两种打破循环依赖的方法:
\n\n在带有属性的第二个实现中,有一个构造函数:public A(IA data, IBefore before)\n。和IA data都是依赖注入方面所IBefore before必需的\xe2\x80\x94 这里是打破 cicle 的最佳点!这是一个可选的实现IBefore:
class A\n{\n public IA Data { get; private set; }\n public IBefore Before { get; set; }\n\n public A(IA data)\n {\n this.Data = data;\n }\n public void Increment()\n {\n // here should be design decision: if Before is optional\xe2\x80\xa6\n if(Before == null)\n {\n Before.DoStuffBefore();\n } \n\n // \xe2\x80\xa6or required\n if(Before == null)\n {\n throw new Exception("\'Before\' is required");\n }\n\n Data.Data++;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n由您决定,如果是可选的,则跳过Before.DoStuffBefore()调用Before,或者在需要时引发异常
根据你的问题:
\n\n