C#中方法重载的不同行为
Posted
技术标签:
【中文标题】C#中方法重载的不同行为【英文标题】:Different behaviour of method overloading in C# 【发布时间】:2011-02-18 18:44:30 【问题描述】:我在浏览 C# Brainteasers (http://www.yoda.arachsys.com/csharp/teasers.html) 时遇到了一个问题:这段代码的输出应该是什么?
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(object o)
Console.WriteLine ("Derived.Foo(object)");
class Test
static void Main()
Derived d = new Derived();
int i = 10;
d.Foo(i); // it prints ("Derived.Foo(object)"
但是如果我把代码改成
class Derived
public void Foo(int x)
Console.WriteLine("Derived.Foo(int)");
public void Foo(object o)
Console.WriteLine("Derived.Foo(object)");
class Program
static void Main(string[] args)
Derived d = new Derived();
int i = 10;
d.Foo(i); // prints Derived.Foo(int)");
Console.ReadKey();
我想知道为什么当我们继承而不是继承时输出会发生变化;为什么在这两种情况下方法重载的行为不同?
【问题讨论】:
【参考方案1】:正如我在answers 页面中指定的那样:
Derived.Foo(object) 被打印 - 选择重载时,如果有任何兼容 在派生类中声明的方法,在基类中声明的所有签名都将被忽略 - 即使它们在同一个派生类中被覆盖!
换句话说,编译器会查看在最派生类中新声明的方法(基于表达式的编译时类型),并查看是否有适用的方法。如果是,它会使用“最好的”可用的。如果不适用,它会尝试基类,依此类推。被覆盖的方法不算在派生类中声明。
有关详细信息,请参阅 C# 3 规范的第 7.4.3 和 7.5.5.1 节。
现在至于为什么要这样指定 - 我不知道。对我来说,派生类中声明的方法优先于基类中声明的方法是有道理的,否则你会遇到“脆弱的基类”问题——在基类中添加一个方法可能会改变代码的含义,使用派生类。但是,如果派生类覆盖基类中声明的方法,它清楚地意识到这一点,因此脆性元素不适用。
【讨论】:
原谅我的无知,但是为什么它考虑使用“object”类型参数的方法是最好的,我认为 int 更接近(就像第二种情况下发生的那样) @Wondering: 是的,int
更好——但是int
重载已经覆盖了基类中的方法,所以它没有被考虑:它不算是在派生类中“新声明”。这就是所有这些解释的重点:)【参考方案2】:
它围绕范围。在第一个程序中,void Foo(int i) 属于类 Base。类 Derived 只是重新定义了它的行为。
Foo(int i) 被忽略,因为它被“借用”并通过从类 Base 继承重新定义。如果 Foo(object o) 不存在,则使用 Foo(int i)。
在第二个程序中,调用 void Foo(int i) 是因为它正确地属于 Derived 类(即它没有通过继承被借用和覆盖)并且具有最适合的签名。
【讨论】:
【参考方案3】:这是因为在考虑基类签名之前,先匹配派生类中的方法签名。因此,当您尝试时:
d.Foo(i);
它会尝试将方法签名与您当前的类(而不是基类)进行匹配。它找到一个可接受的匹配 Foo(object)
并且不进一步考虑基类方法签名。
这完全是关于编译器找到匹配的方法签名,以及它用来查找这些签名的搜索顺序。
-道格
【讨论】:
令人惊讶的是它不在派生类中包含重写方法。这仍然是“派生类中的方法签名”,但不算在派生类中声明。 "它找到了一个可接受的匹配 Foo(object)" 但是,Foo(int) 也是可接受的匹配 是的,但正如 Jon 所说,Foo(int) 没有在派生类中声明(即使它被覆盖,这不算在内)。以上是关于C#中方法重载的不同行为的主要内容,如果未能解决你的问题,请参考以下文章