如何调用重写的虚方法的"基本实现"?

mac*_*nir 71 c# oop

鉴于以下代码,有没有办法可以调用类A的方法X版本?

class A
{
  virtual void X() { Console.WriteLine("x"); }
}

class B : A
{
  override void X() { Console.WriteLine("y"); }
}

class Program
{
  static void Main()
  {
    A b = new B();
    // Call A.X somehow, not B.X...
  }
Run Code Online (Sandbox Code Playgroud)

Pet*_*ete 114

使用C#语言结构,您无法从or 的范围显式调用基函数.如果你确实需要这样做,那么你的设计就有一个缺陷 - 即该函数不应该是虚拟的,或者应该将基本函数的一部分提取到单独的非虚函数中.AB

你可以从BX 内部调用AX

class B : A
{
  override void X() { 
    base.X();
    Console.WriteLine("y"); 
  }
}
Run Code Online (Sandbox Code Playgroud)

但那是另一回事.

正如Sasha Truf在这个答案中指出的那样,你可以通过IL来做到这一点.你可以通过反思完成它,正如mhand在评论中指出的那样.

  • (嗨.只是为了记录,有人删除了我添加的'愚蠢技巧的标签,然后其他人删除了指出它的评论,使它看起来像我真的想要/需要这样做.获得通知会很有用人们似乎想在SO上做的愚蠢编辑.) (7认同)

Sas*_*ruf 13

您无法通过C#执行此操作,但您可以编辑MSIL.

方法的IL代码:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 1
    .locals init (
        [0] class MsilEditing.A a)
    L_0000: nop 
    L_0001: newobj instance void MsilEditing.B::.ctor()
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: callvirt instance void MsilEditing.A::X()
    L_000d: nop 
    L_000e: ret 
}
Run Code Online (Sandbox Code Playgroud)

您应该将L_0008中的操作码从callvirt更改call

L_0008: call instance void MsilEditing.A::X()
Run Code Online (Sandbox Code Playgroud)


Joh*_*lla 9

你可以这样做,但不是你指定的那一点.在上下文中B,您可以A.X()通过调用来调用base.X().


Jor*_*oba 8

你不能,你不应该.这就是多态性的用途,因此每个对象都有自己的方式来做一些"基础"事情.


Zoh*_*led 8

如果该方法在派生类中声明为overrides. 为此,派生类中的方法应声明为new

public class Base {

    public virtual string X() {
        return "Base";
    }
}
public class Derived1 : Base
{
    public new string X()
    {
        return "Derived 1";
    }
}

public class Derived2 : Base 
{
    public override string X() {
        return "Derived 2";
    }
}

Derived1 a = new Derived1();
Base b = new Derived1();
Base c = new Derived2();
a.X(); // returns Derived 1
b.X(); // returns Base
c.X(); // returns Derived 2
Run Code Online (Sandbox Code Playgroud)

在这里看到小提琴

  • 我觉得这应该是这个问题的答案。如果您更改“覆盖”该方法的方式,使其成为具有相同签名的新方法,那么其他一切都应该正常工作。 (3认同)

小智 6

我知道现在是历史问题。但对于其他谷歌员工:你可以写这样的东西。但这需要改变基类,这使得它对外部库毫无用处。

class A
{
  void protoX() { Console.WriteLine("x"); }
  virtual void X() { protoX(); }
}

class B : A
{
  override void X() { Console.WriteLine("y"); }
}

class Program
{
  static void Main()
  {
    A b = new B();
    // Call A.X somehow, not B.X...
    b.protoX();


  }
Run Code Online (Sandbox Code Playgroud)