在基类中将ToString标记为虚函数,会发生什么?

3
考虑以下(LinqPad)示例。类X中的ToString被标记为虚拟的。为什么这里输出不等于“Hi,I'm Y,Hi,I'm X”,而是打印了类型名?当然,标记ToString为虚拟的是错误的,因为它在Object中已经被定义为虚拟的,我只是想理解这里发生了什么。
void Main()
{
    Y y = new Y();
    Console.WriteLine(y);
}

// Define other methods and classes here

class X
{
  public virtual String ToString() 
  {
    return "Hi, I'm X";
  }
}

class Y : X
{
  public override String ToString() 
  {
    return "Hi, I'm Y, " + base.ToString();
  }
}

1
这里有一个关于虚拟和非虚拟方法的很棒的演示:http://msdn.microsoft.com/en-us/library/aa645767%28v=vs.71%29.aspx - Brad Christie
2个回答

15

那会在X中创建一个新的虚拟方法名为ToString(),它将隐藏Object.ToString()。因此如果你有:

Y y = new Y();
X x = y;
Object o = y;

Console.WriteLine(y.ToString()); // Shows "Hi, I'm Y, Hi, I'm X";
Console.WriteLine(x.ToString()); // Shows "Hi, I'm Y, Hi, I'm X";
Console.WriteLine(o.ToString()); // Calls object.ToString; shows just "Y"

仅调用

Console.WriteLine(y);

这与最后一行是等效的,这就是为什么类型名称被打印的原因。

基本上,你的X.ToString方法应该覆盖object.ToString()方法:

public override String ToString() 
{
    return "Hi, I'm X";
}

8
通过在`class X`上使用`virtual String ToString()`,你"隐藏"了`object.ToString`而不是覆盖它。
当你调用`Console.WriteLine(y);`时,它调用的是`object.ToString()`。由于您没有覆盖这个方法,所以您的方法永远不会被调用。
话虽如此,编译器会提醒你:
``` Warning 1 'X.ToString()' hides inherited member 'object.ToString()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. ```

LinqPad 没有警告信息...真希望它们在那里 ;)。 - Michiel Borkent
尝试一下最新的 LINQPad beta(www.linqpad.net/beta.aspx)-现在它应该显示警告。 - Joe Albahari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接