2015-08-14 55 views
3

我有一个类从另一个类继承,以允许使用可为空的值。但是,当我以不可为空的值使用它时,它无论如何都会使用重载为空。混淆超载分辨率

我不明白为什么C2类的功能掩盖C1类的功能在这个代码:

class c1 
{ 
    public void fn1(int value) 
    { 
     Console.WriteLine("value {0} is normal", value); 
    } 
    public void fn1(int? value) 
    { 
     Console.WriteLine("value {0} is nullable", value); 
    } 
    public void fn2(int value) 
    { 
     Console.WriteLine("value {0} is normal", value); 
    } 
} 
class c2: c1 
{ 
    public void fn2(int? value) 
    { 
     Console.WriteLine("value {0} is nullable", value); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     c1 o1 = new c1(); 
     c2 o2 = new c2(); 
     int val = 10; 
     o1.fn1(val); 
     o2.fn1(val); 
     o2.fn2(val); 
     Console.ReadLine(); 
    } 
} 

,其结果是:

value 10 is normal. 
value 10 is normal. 
value 10 is nullable. 

然而C2具有功能FN2 (INT)。

+0

有时你可以用投歧义这一点。如果你的fn2函数被交换了,那么用一个强制转换调用将会选择正确的函数o2.fn2((int?)val); – CRice

回答

2

这是我在Jon Skeet的博客上找到的。

继承会导致混淆。当编译器寻找方法重载时, 会考虑调用的“目标”类的编译时间 ,并查看那里声明为 的方法。如果找不到合适的东西,它会查看父类 类......然后是祖父类,等等。这意味着如果在层次结构的不同层次上有两种方法,“更深”的 将会应首先选择,即使它不是该呼叫的“更好的功能成员”。

http://csharpindepth.com/Articles/General/Overloading.aspx

0

您的功能的解析遵循您的类层次结构。在这个例子中,你发布的函数c2 :: fn2与你的调用o2.fn2(val)匹配,因为它已经在c2中显式定义,并且编译器可以隐式地将int转换为int?实际上你隐藏了c1 :: fn2。

你可以看看如何让你的c1类抽象(sans实现)或在c2中使用override来虚拟。

2

正如许多边缘情况属实,也没有猜到“为什么”给它,它只是如何C#规范编写的。他们可以通过其他方式做到这一点,但决定这样做。 https://msdn.microsoft.com/en-us/library/aa691336(v=vs.71).aspx

最相关的部分(从上面链接C#规范的“7.4.2重载分析”,不同版本规范的可能在其他部分类似的文本):

的候选集合的一个方法调用不包括...在基类中的方法不是候选如果在派生类中的任何方法适用

0

好比说Handoko.Chen,在乔恩斯基特的博客,我们可以找到

编译器会忽略孩子中的重写方法。

所以我发现的唯一途径是隐藏继承方法:

class c2: c1 { 
    public void fn2(int? value) { 
     Console.WriteLine("value {0} is nullable", value); 
    } 
    public new void fn2(int value) { 
     base.fn2(value); 
    } 
}