2010-01-10 12 views
0

我只是讀這個答案重載完成在編譯時

Which overload is called and how?

由喬恩飛碟雙向,我只是做了瞭解重載決議得到在編譯時完成 - 這怎麼可能?你不知道對象的類型,直到你運行?

我始終認爲,所有的方法都調用運行時(後期綁定)

哪些例外情形做?

我會舉一個例子:

public void DoWork(IFoo) 
public void DoWork(Bar) 

IFoo a = new Bar(); 
DoWork(a) 

哪一種方法被稱爲在這裏,爲什麼?

回答

2

當編譯器遇到方法調用時,所有參數的類型都是已知的,因爲C#是一種靜態類型語言:所有表達式和變量都是特定類型,且該類型是確定的並且在編譯時已知。

這是忽略dynamic這稍微複雜的東西。

編輯:這是對您編輯的回覆。爲了清楚起見,我翻譯你的代碼如下:

interface IFoo { } 
class Bar : IFoo { } 
class Test { 
    public void DoWork(IFoo a) { } 
    public void DoWork(Bar b) { } 
} 

class Program { 
    static void Main(string[] args) { 
     IFoo a = new Bar(); 
     Test t = new Test(); 
     t.DoWork(a); 
    } 
} 

你問時爲t.DoWork(a)Main調用該方法在這裏(Test.DoWork(IFoo)Test.DoWork(Bar))調用。答案是Test.DoWork(IFoo)被調用。這基本上是因爲參數輸入爲IFoo。讓我們去規範(§7.4.3.1):

的函數成員被認爲是適用的功能部件相對於當以下爲真參數列表答:

數A中的參數與函數成員聲明中的參數數量相同。

對於A中的每個參數,所述參數的參數傳遞模式(即,值,參考,或流出)等同於相應的參數的參數傳遞模式,並且

爲值參數或一個參數數組,參數存在從參數到相應參數

的隱式轉換(第6.1節),對於ref或out參數,參數的類型與相應參數的類型相同。畢竟,ref或out參數是傳遞參數的別名。

此處的問題(請參閱粗體語句)是沒有從IFooBar的隱式轉換。因此,方法Test.DoWork(Bar)不是適用的功能成員。很明顯,Test.DoWork(IFoo)是一個適用的函數成員,並且作爲唯一的選擇,編譯器將選擇它作爲調用的方法。

3

我想你是混淆重載分辨率virtual method dispatch。是的,該對象的運行時類型將決定運行哪種方法,但該方法已被編譯器綁定。這是一種允許多態行爲的類型安全方式,沒有真正的後期綁定的靈活性和危險性。

編譯器將根據代碼中寫入的參數類型確定調用哪個方法。

2

虛擬方法(包括通過接口的調用)在運行時(後期綁定)在接收器的類型上分派。

使用編譯時類型的引用在編譯時解析非虛擬方法。這就是爲什麼陰影(new修飾符)會導致不同的行爲,具體取決於是通過基類引用還是派生類引用調用陰影方法。

在所有情況下,重載解析都使用參數的編譯時類型。只有接收方 -形式的呼叫中的x - 才被考慮用於後期綁定。因此,如果y被輸入爲對象,並且唯一的重載爲string yint y,則編譯器將會出錯,即使在運行時y實際上是字符串或int - 因爲它只考慮編譯時間類型(變量的聲明類型)。

1

在運行時唯一決定的是「虛擬」功能,您可以爲您的對象調用適當的函數。