2015-08-14 52 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); 
    } 
}