2

当我调用下面的代码行时,它从 ClassB 执行 Get()。

该对象被创建为ClassC,它作为带有new关键字的方法。理想情况下,它应该Get()ClassC.

Main()
{
      ClassA obj = new ClassC();
      lbl.Text = obj.Get();
}


public class ClassA
{
  public virtual string Get()
  {
    return "from A";
  }
}

public class ClassB : ClassA
{
  public override string Get()
  {
    return "from B";
  }
}

public class ClassC : ClassB
{
  public new string Get()
  {
    return "from C";
  }
}

谁能帮我找出原因。

4

7 回答 7

3

关键是 中的new关键字ClassC。如果对象被处理为 a ,编译器将使用它ClassC来掩盖原始Get()函数。

如果对象是ClassA引用,Get()则将作为原始对象处理Get(),从而导致在 中的Get()覆盖ClassB

于 2012-08-27T13:08:00.963 回答
1

魔术称为虚拟调度。

ClassB覆盖ClassA Get,这意味着系统知道ClassA有一个具有不同实现的后代Get。当Get在 type 的引用上调用时ClassA,它将检查该引用是否为 factClassB或后代,并改为执行该代码。

当然,这是(有点)递归的,所以如果ClassB有任何后裔覆盖Get,那些Get's 将被调用,等等......

这里的问题是Get定义的 inClassC与andGet中引用的不同,而是一个全新的方法(因此是关键字),恰好具有相同的名称。ClassAClassBnew

因此,当obj.Get()被调用时,系统不会走得那么远,ClassC而只会起床ClassB并执行它。如果您想ClassC.Get()被执行,您可以将 更改newoverride,或尝试通过ClassC引用调用它,例如((ClassC)obj).Get()

于 2012-08-27T13:15:56.837 回答
1

具有不同的ClassC.Get签名(新字符串)并且缺少覆盖,因此它不会覆盖ClassA.Get.

于 2012-08-27T13:08:11.677 回答
0

在这种情况下的new关键字是一个 hider..

这通常在您的基类有一个虚拟方法并且您希望与基类虚拟方法名称相同而不覆盖它的情况下使用。

如果您在派生类中声明此类方法而不覆盖基类方法和 new 关键字,编译器将生成警告

如果您不使用new修饰符,编译器会生成警告。

new 修饰符告诉编译器重复成员不是意外,因此编译器不会显示警告

于 2012-08-27T13:16:11.107 回答
0

您可以先看看带有 override 和 new 的版本控制ClassA引用将从Get()原始类处理。由于此类型已被覆盖ClassB,因此将调用Get() of 。

ClassCreference 将Get()作为方法处理,因此方法 inClassC将被调用

static void Main(string[] args)
{
     ClassA obj = new ClassC(); 
     Console.WriteLine(obj.Get());  // will print out "from B"

     ClassC obj2 = new ClassC(); 
     Console.WriteLine(obj2.Get());  // will print out "from C"
}
于 2012-08-27T13:18:23.680 回答
0

仅当您不先将其转换为 ClassA 时,它才会从 ClassC 调用 Get()。Get() 的最后一个虚拟实现是来自 ClassB 的 Get(),当您从 A 调用虚拟 Get() 方法时会调用它。

于 2012-08-27T13:09:21.137 回答
0

new关键字遮蔽了继承的方法。但是,只有当对象的编译时类型是 type 时,它​​才会这样做ClassC。在您的情况下,编译时类型会ClassA导致使用继承的版本。

new这就是为什么在使用关键字隐藏继承的成员之前应该仔细考虑的原因之一。根据持有实例的变量的声明类型,可能会调用不同的方法:

ClassA a = new ClassC();
ClassC c = (ClassC)a; // Note, this is the SAME instance as in a
Assert.AreSame(a, c);

Console.WriteLine(a.Get()); // prints "from B"
Console.WriteLine(c.Get()); // prints "from C"
于 2012-08-27T13:09:50.213 回答