打印以下程序
A:C(A,B) B:C(A,B)
(正如它应该)
public interface I { string A(); } public class C : I { public string A() { return "A"; } public string B() { return "B"; } } public class A { public virtual void Print(C c) { Console.WriteLine("A:C(" + c.A() + "," + c.B() + ")"); } } public class B : A { public new void Print(C c) { Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")"); } public void Print(I i) { Console.WriteLine("B:I(" + i.A() + ")"); } } class Program { public static void Main(string[] args) { A a = new A(); B b = new B(); C c = new C(); a.Print(c); b.Print(c); } }
但是,如果我在B类中将关键字'new'更改为'override',如下所示:
public override void Print(C c)
突然之间的程序开始打印:
A:C(A,B) B:I(A)
为什么?
这与如何解决重载方法有关.
有效地(稍微简化),编译器首先查看表达式(B)的声明类型,并查找首先在该类型中声明的候选方法.如果有任何适当的方法(即所有参数都可以转换为方法的参数类型),那么它不会查看任何父类型.这意味着如果在派生类型中存在任何"新近声明的"适当方法,则初始声明在父类型中的重写方法不会获得查找.
这是一个稍微简单的例子:
using System; class Base { public virtual void Foo(int x) { Console.WriteLine("Base.Foo(int)"); } } class Derived : Base { public override void Foo(int x) { Console.WriteLine("Derived.Foo(int)"); } public void Foo(double d) { Console.WriteLine("Derived.Foo(double)"); } } class Test { static void Main() { Derived d = new Derived(); d.Foo(10); } }
这版画Derived.Foo(double)
-即使编译器知道有型的参数的匹配方法int
,和参数的类型int
,并将其从转换int
到int
从比转换"更好" int
来double
,只有事实Foo(double)
的方法最初宣布在Derived
表示编译器忽略Foo(int)
.
这是非常令人惊讶的IMO.我可以看到为什么它会是如果案件Derived
没有重载Foo
-否则将在基类一个新的,更具体的,方法可能会意外更改的行为-但显然Derived
这里知道有关Base.Foo(int)
,因为它的覆盖它.这是(相对较少)的一点,我认为C#设计师做出了错误的决定.