2009-12-02 24 views
2

關於這種事情,已經有一些帖子已經對堆棧溢出了,但並不完全一樣 - 如果事先已經得到回答,請事先道歉。通過IEnumerable進行的推斷類型<T>

爲什麼這個不行:

public class MyBase { } 

public class MyUtils 
{ 
    public bool Foo<T> (T myObject) { return true; } 
    public bool Foo (MyBase myBaseObject) { return false; } 

    public void Go<T> (IEnumerable<T> items) 
    { 
     foreach (var item in items) 
     { 
      // this test fails 
      Assert.IsFalse (Foo (item)); 
     } 
    } 
} 

如果我致電上述圍棋(),並通過在MyBase對象的負荷,每次調用美孚將調用通用美孚(),它返回true。

new MyUtils().Go (new MyBase[] { new MyBase(), new MyBase() });  

爲什麼它不調用專門的MyBase版本呢?如果我直接調用Foo(new MyBase()),它會正確地推斷出要調用哪個。這是因爲C#3中的集合缺乏協變性,還是我只是很傻而且沒有正確地做到這一點?

謝謝!

艾薩克

+1

重載解析是在編譯時完成的,並且在編譯時,每個'item'都是T類型的,它不知道它們中的任何一個都是特定的MyBase。 – meandmycode 2009-12-03 13:43:35

+0

@meandmycode - 你應該將其作爲回答(鏈接http://msdn.microsoft.com/en-us/library/aa691336%28VS.71%29.aspx) – 2009-12-03 14:00:32

+0

謝謝你。難道它在編譯時不知道它是MyBase類型的,因爲我傳入的集合被輸入到MyBase中? – 2009-12-04 15:26:44

回答

1

它不叫「專業」之一,因爲編譯器的動產調用哪個方法當程序(在這種情況下,是Go功能)是編譯它的運行時。

當編譯器編譯Go函數時,唯一的信息是有一些類型爲T的對象。它不知道你可能在稍後的某個時間點提供一個MyBase類型的對象。它唯一的選擇是選擇Foo<T>重載,所以它烘烤了編譯好的程序。

如果您希望應用程序在運行時選擇重載,並通過在應用程序運行時查看對象來選擇最佳重載,那就稱爲「動態分派」,並且只能用於動態語言,如Ruby ,Python,PHP等。

C#3完全是靜態的,不支持它。如果你想以這種方式工作,你必須在你的代碼中寫一個if語句來檢查類型。另一方面,C#4有一些動態的支持。如果你正在寫在C#4這個代碼,你可以聲明如下「轉到」功能:

public void Go<T> (IEnumerable<dynamic> items) 

然後,它會使用動態分配在運行時選擇哪個超載被調用,並且會叫超載專門採取MyBase

+0

獵戶座 - 感謝您的答案。幾天前,我似乎也得出了同樣的結論...... http://isaac-abraham.spaces.live.com/blog/cns!2FBCF8017242E87B!4618。條目 感謝您的確認,雖然:) – 2009-12-06 15:17:46

0

根據C#規範(7.4.3.2),非通用方法比普通的一個更好的,所以它應選擇。

但是,我認爲通用的一個是在你的情況下,因爲它是在一個泛型調用上下文中調用的(「foreach」循環)。