【问题标题】:Sending base class to a method which receives derived class - c#将基类发送到接收派生类的方法 - c#
【发布时间】:2026-02-11 11:40:01
【问题描述】:

我有一个基类和两个派生类。我有一个基类变量,它可以包含一个派生类。我想将该变量发送到接收派生类的方法。

由于我不知道变量包含什么,我可以在没有显式转换的情况下解决这个问题吗?

代码:

Class A{ 
    virtual public void foo1() {/.../}
}
Class B : A{
    override public void foo1() {/.../}
}
Class C : A{
    override public void foo1() {/.../}
}
Class D{
   public foo(B argB) {/.../}
   public foo(C argC) {/.../}   

// in main
D varD = new D();
A varA = new B();   

varD.foo(varA); //--->> Problem here need explicit casting
A varC = new C();
varD.foo(varC);  //--->> Problem here need explicit casting

我不知道要发送给varD.foo 的派生类,并且我希望对不同派生类进行不同的处理。我能做什么?

【问题讨论】:

  • 这段代码能编译吗?我没有看到任何 varB 声明。
  • 试试visitor pattern
  • AbZy,对不起,这是我的错误,我修复了代码
  • 根据fooD 重载正在做什么,您可能可以考虑访问者模式,或者另一个知道如何处理@987654326 的不同子类的合作者@.
  • 为什么我会觉得foo(B argB) 包含argB.foo1()?重构以利用多态性。

标签: c# inheritance polymorphism


【解决方案1】:

这不是多态性的意义所在——即使显式强制转换,您也不能将基类传递给需要专用类的地方。多态以另一种方式工作:您可以在需要基类的任何地方传递一个专门的类。

你应该做的是让D.foo 期待A,你会自动好起来的。如果您向BC 添加任何在A 中没有基本实现的方法,则无论如何都需要传递B,并且不能将A 转换为BD

【讨论】:

  • 如果D 基于BC 做了一些特殊的事情,那么将它们发送到单个方法是不够的。可能需要另一层抽象。
  • 感谢 @Servy 编辑我的答案 - 虽然编辑是正确的并改进了我的答案,但我实际上不太喜欢我的答案被编辑。下次,请在评论中建议编辑,我将自己进行编辑。所以我总能确定这里写的就是我所说的:-)
  • @AnthonyPegram:真的吗?如果D.foo 期望A 作为参数然后根据if (a is B) ... else if (a is C) ... 选择执行路径,那会不会行不通?
  • @ThorstenDittmar 这不是 SO 的工作方式。这是一个协作网站,您无权不编辑您的答案。在本网站上发帖即表示您允许任何用户编辑您的帖子。请参阅this FAQ entry 了解更多信息。
  • 我只是要求你不要这样做,因为我不喜欢它。你可以表现出尊重,也可以不表现出来。但我仍然有权要求。
【解决方案2】:

只需将foo 设为A 的抽象实例方法,并覆盖BC 中的实现即可。您甚至可以保留您的班级 D 并将实际工作委派给那里,但这取决于这是否是个好主意。

这里是委托给D的代码。另请注意,我在所有类中都省略了方法foo1()

public abstract class A
{ 
    public abstract void foo(D d);
}

public sealed class B : A
{
    public override void foo(D d)
    {
        d.foo(this);
    }
}

public sealed class C : A
{
    public override void foo(D d)
    {
        d.foo(this);
    }
}

public sealed class D
{
   public void foo(B b) { [...] }
   public void foo(C c) { [...] }   
}

现在您可以使用虚拟方法调度来调用正确的方法。

D d = new D();

A b = new B();   
A c = new C();

b.foo(d); // Calls B.foo(D) and in turn D.foo(B).
c.foo(d); // Calls C.foo(D) and in turn D.foo(C).

【讨论】:

  • abstract有关系吗? BC 无论如何都会覆盖该方法。
  • 有问题的方法是D.foo(B)D.foo(C),不是A 层次结构中的方法之一。
  • 啊,我明白了。您的意思是完全删除类 D 并让 BC 实现自己的 foo
  • 没有必要有A abstract - 你可以有一个虚拟的实现。但如果可能,A 应该是抽象的。您可以摆脱D,但没有必要 - 查看添加的代码。