2011-02-12 188 views
16

好了,所以我是一個Java的人開始使用C#和我的編碼,並開始做一個通用的方法和我寫的運行和編譯,但它違揹我知道泛型應該如何工作的一切所以我希望有人可以給我講解一下:C#泛型方法不指定類型

所以我有一個通用的方法定義如下:

public static List<T> CopyAsList<T>(IEnumerable<T> list, Object lockObject) 
{ 
    if (list != null) 
    { 
     lock (lockObject) 
     { 
      return new List<T>(list); 
     } 
    } 
    return null; 
} 

但奇怪的事情對我來說,我可以把這個泛型方法而沒有指定T,它會工作:

List<String> strings = new List<string>() { "a", "b", "c"}; 
List<int> ints = new List<int>() { 1,2,3}; 
object lockObject = new object(); 

foreach (string s in CopyAsList(strings, lockObject)) 
{ 
    Console.WriteLine(s); 
} 

foreach (int i in CopyAsList(ints, lockObject)) 
{ 
    Console.WriteLine(i); 
} 

它是如何的代碼能而沒有指定泛型類型編譯? C#在運行時推斷類型嗎?

+6

在運行時沒有C#了。 – Gabe

+0

C#編譯器在編譯時推斷類型。注意,CLR(DLR)可以在運行時推斷出類型,請參閱C#中的'dynamic'關鍵字。 – kizzx2

+1

kizzx2:OP用'.net-3.5'標記了問題,它從上下文中消除了'dynamic',並且在運行時沒有類型推理--DLR使用反射來確定類型。 – Gabe

回答

35

沒有,可以推斷在編譯的時候 - 在你提供的IEnumerable<T>泛型類型參數時,它在編譯時是已知的。一般來說,關於泛型和類型參數的所有內容都是在編譯時指定的。如果有任何類型的不匹配,編譯器抱怨並且您的代碼不會編譯。

存在邊緣情況,您必須明確指定類型,這些情況只發生在重載方法的罕見情況下,有時會帶有多個類型參數組合。

+0

其中一種情況是,當方法的任何參數都是動態類型的時 - 即使所有相同的線索都存在,一旦你在那裏拋出所有編譯器泛型類型推斷出現在窗口外面。 –

11

C#的編譯器通常可以在編譯時推斷一般類型。當它可以做到這一點時,你不需要爲泛型方法指定類型。

這是什麼使LINQ「可用」的重要組成部分。如果沒有編譯時類型推斷,查詢看起來像:

IEnumerable<int> myIds = myCollection 
          .Where<MyType>(i => i.Name == "Foo") 
          .Select<MyType, int>(i => i.Id); 

而不是能寫:

var myIds = myCollection.Where(i => i.Name == "Foo").Select(i => i.Id); 
+3

和匿名類型的查詢將是不可能的,而且,如果類型不能被編譯器推斷,代碼將不會編譯。 – Femaref

+0

如果沒有類型推斷,編譯器將不知道這些lambda將具有哪些類型。 – Gabe

12

C#有一個偉大的更多的編譯時和運行時類型推斷的功能比Java。如果這個問題你感興趣,請參閱我的文章的題目:

http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/

如果你特別感興趣泛型方法的類型推斷和你有一個半小時的空閒時間,這裏是我解釋我們是如何改變C#3中的類型推斷算法:

http://blogs.msdn.com/b/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx

+0

「運行時類型推斷功能」你在說什麼功能?與「動態」有關的東西? – CodesInChaos

+0

@CodeInChaos:是的,C#中的「dynamic」意思是「在運行時解析這個表達式的類型分析,而不是編譯時間」。 –

+0

我知道'dynamic'的作用。我只是想知道你是否在討論'dynamic'特性之外的某種運行時類型推斷。 – CodesInChaos