C# 关于继承和循环依赖的问题

C# 关于继承和循环依赖的问题,c#,inheritance,dll,C#,Inheritance,Dll,昨天在工作中遇到了一个非常有趣的问题 我有两个不同的课程,分别是Foo和Bar。每个人都有自己的C#library项目(单独的DLL) Bar包含一个虚拟方法: public class Bar { public virtual void DoSomething(); } Foo在其构造函数中使用Bar的实例来设置内部属性: public Foo (Bar myBar) { m_Bar = myBar; } 显然,Foo引用了Bar的项目 现在,我还有5个其他类,每个类

昨天在工作中遇到了一个非常有趣的问题

我有两个不同的课程,分别是Foo和Bar。每个人都有自己的C#library项目(单独的DLL)

Bar包含一个虚拟方法:

public class Bar
{
     public virtual void DoSomething();
}
Foo在其构造函数中使用Bar的实例来设置内部属性:

public Foo (Bar myBar)
{
      m_Bar = myBar;
}
显然,Foo引用了Bar的项目

现在,我还有5个其他类,每个类都位于自己的project/dll中。我们将它们称为A、B、C、D和E。A-E都是从类Bar中派生出来的子类,它们各自包含DoSomething()的重写实现。因为它们是从Bar子类化的,所以它们中的任何一个都可以作为Foo构造函数的参数

A-E各自维护一个Foo实例的内部集合。例如,我会在课堂上做这样的事情:

myFooCollection.Add(new Foo(this));
因此,类A-E都需要对Foo的project/dll的引用

现在,切换回Foo一会儿,让我们假设在构造函数中设置Bar属性后,我需要调用该Bar的DoSomething()方法:

public class Foo (Bar myBar)
{
     m_Bar = myBar;
     m_Bar.DoSomething();
}
请记住,例如,类A被用作构造函数的Bar参数。我对DoSomething()的调用需要执行A对该方法的实现。但是,由于构造函数参数是父类Bar的参数,而Foo不知道类A-E(我不能给它一个引用而不引起循环依赖),因此它将调用父类Bar中的虚方法。自然的解决办法是在打电话之前先向孩子们倾诉:

(A)m_Bar.DoSomething();

但这也是不可能的,因为Foo再次对这组儿童课程一无所知。这就是我的困境。整个项目结构不能改变,因为很明显,这个系统比我在这里介绍的要大得多,复杂得多。但我的要求还是一样的。Foo需要能够访问DoSomething()的子实现才能正常运行。如何解决这个问题有什么想法吗?如果为了更好地理解问题而需要任何澄清,请让我知道,我将尝试进一步阐述。

您不允许有项目的静态循环参考;但是,可以有实例的动态循环引用。如果调用
m_Bar.DoSomething()然后,由于多态性,将自动调用正确的实现。如果
mubar
Bar
,则将调用
Bar
的实现。如果
mubar
a
,则将调用
a
的实现。
Bar
Foo
都不需要通过
E
知道类
A
的存在


更新:(见下文评论)


不允许有项目的静态循环引用;但是,可以有实例的动态循环引用。如果调用
m_Bar.DoSomething()然后,由于多态性,将自动调用正确的实现。如果
mubar
Bar
,则将调用
Bar
的实现。如果
mubar
a
,则将调用
a
的实现。
Bar
Foo
都不需要通过
E
知道类
A
的存在


更新:(见下文评论)


还值得一提的是,在运行时使用反射派生子类型在我的系统上下文中不是解决此问题的有效方法。能否为子类Bar.DoSomething methods()包含方法存根?抱歉,我不能在线共享类似的内容,因为它是用于工作的。方法存根不应该改变整个问题。在子类DoSomething()方法中,重写使用了什么语法?重写还是新建?如果在子类中使用new,这可能是问题的原因。还值得一提的是,在运行时使用反射派生子类型在我的系统上下文中不是解决此问题的有效方法。是否可以为子类Bar.DoSomething methods()包含方法存根对不起,我不能在网上分享这样的东西,因为这是为了工作。方法存根不应该改变整个问题。在子类DoSomething()方法中,重写使用了什么语法?override还是new?如果在子类中使用new,这很可能是问题的原因。这是我开始研究这个问题时假设的,但是我非常仔细地验证了,在使用A构造Foo实例并调用DoSomething之后,它调用了父方法,并且没有发生多态性,这是不可能的。如果您在派生类中重写了
DoSomething
(而不仅仅是创建了一个新的
DoSomething
方法)。然后将调用重写的方法。您必须使用
override
关键字,而不是
new
关键字。(注意:通过键入“override”,InElisense将向您显示一个可重写方法和属性的列表,并自动为您创建一个被重写的方法或属性。)我刚刚编写了一个简单的控制台应用程序,您所说的是真的(这是我从一开始就预期会发生的事情,当它没有发生时,我感到震惊)。我一定错过了导致这一切发生的原因。也许这是一个新的vs a覆盖,但我后来进行了重大的其他更改,因此很难返回并检查遗漏的内容。这是我在开始工作时的假设,但是我非常仔细地验证了,在使用a构造一个Foo实例,然后调用DoSomething之后,它调用了父方法,没有多态性发生了这是不可能的。如果您在派生类中重写了
DoSomething
(而不仅仅是创建了一个新的
DoSomething
方法)。然后将调用重写的方法。您必须使用
覆盖
关键字
public class A : Bar
{
     public override void DoSomething()
     {
         Console.WriteLine("I am an 'A'");
     }
}