[譯]分辨差別 -- 第一部分: 泛型不是模板
譯自Eric Lippert's Blog, 原文: http://blogs.msdn.com/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx
因為我不是常人, 所以我喜歡去了解容易混淆的東西間的微妙差別:
- 我的腦袋裡還是非常地不明白集線器,路由器和交換機之間的區別,並且也不明白他們怎麼在裡面聯絡起來的。
- 找到的大塊的礦石事實上是岩石;只要你把它們用於花園或建造一座橋樑, 它們就突然變成了石料。
- 當一隻豬達到了120磅,它就是一隻肥豬。
我想我可以為程式語言設計中一些容易困惑的概念做一個小系列.
這裡是一個我經常遇到的問題:
public class C
{
public static void DoIt
{
ReallyDoIt(t);
}
private static void ReallyDoIt(string s)
{
System.Console.WriteLine("string");
}
private static void ReallyDoIt
{
System.Console.WriteLine("everything else");
}
}
當你呼叫C.DoIt
C#語言標準說當你需要面臨選擇呼叫ReallyDoIt
因為那不是標準所說的選擇。如果你說要呼叫ReallyDoIt("hello world");
那麼我們會選擇非泛型的版本。但是你並不是把編譯器所知道的string型別進行引數傳遞。你只是傳遞了型別T,一個沒有約束的型別引數,所以它可以是任何型別。所以由於過載決議的演算法,有沒有一個方法能接收任何型別作為引數呢?回答是有。
這個C#裡泛型的例子並不像C++裡面的模板。你可以把模板想象成一個奢華的搜尋替代的機制。當你說你要在模板中呼叫DoIt
泛型可不是這麼工作的。泛型是這樣的,好吧,一般的。我們只做一次過載決議然後固定了結果。當任何程式從一個完全不同的程式集用string作為型別引數呼叫到這個方法的時候,我們不會在執行時改變它。我們為泛型生成的IL程式碼已經定好了將要去選出呼叫的方法。那個JIT並不是說“好吧,如果我們讓C#編譯器用這個額外資訊去馬上執行我碰巧就知道了,那麼它就會挑一個不同的過載. 讓我重寫一下生成的(IL)程式碼吧,讓編譯器忽略以前生成的”。 JIT是不知道任何C#的條條框框的。
本質上來說,上面的例子和這個沒有區別:
public class C
{
public static void DoIt(object t)
{
ReallyDoIt(t);
}
private static void ReallyDoIt(string s)
{
System.Console.WriteLine("string");
}
private static void ReallyDoIt(object t)
{
System.Console.WriteLine("everything else");
}
}
當編譯器為呼叫ReallyDoIt生成(IL)的時候, 它會挑選object作為引數的版本,因為那是它最好的選擇。如果有人用string來呼叫方法,那麼它還是會選擇object作為引數的版本。
現在,如果你確實想根據引數的型別在執行時做過載決議,我們能為你做到。那就是C# 4.0的新特性dynamic能做的。只要把object替換成dynamic, 那麼當你呼叫那個object的方法時, 我們會在執行時根據它所知道的所有的執行時型別,執行過載決議並且動態地生成編譯器選擇的呼叫程式碼。
原文地址:http://blog.joycode.com/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-616443/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [譯]分辨差別 -- 第三部分: fixed 和 fixed
- [譯]分辨差別 -- 第二部分: 作用域, 定義空間和 生存期
- python中分辨int和float的差別Python
- C++泛型一:模板C++泛型
- 型別 VS 泛型型別泛型
- TypeScript 泛型型別TypeScript泛型型別
- 菜鳥譯文(二)——使用Java泛型構造模板方法模式Java泛型模式
- 【譯】Swift 泛型宣言Swift泛型
- 【譯】在非泛型類中建立泛型方法泛型
- TypeScript 官方手冊翻譯計劃【六】:型別操控-泛型TypeScript型別泛型
- 泛型型別(.NET 指南)泛型型別
- 匿名型別是不是強型別?型別
- 泛型類、泛型方法、型別萬用字元的使用泛型型別字元
- Java™ 教程(泛型原始型別)Java泛型型別
- 型別與泛型標記型別泛型
- Scala 泛型型別和方法泛型型別
- Java泛型與型別擦除Java泛型型別
- TypeScript 官方手冊翻譯計劃【十一】:型別操控-模板字面量型別TypeScript型別
- [譯]Kotlin泛型中何時該用型別形參約束?Kotlin泛型型別
- 【譯】9. Java反射——泛型Java反射泛型
- Java泛型型別擦除問題Java泛型型別
- TypeScript 基本型別和泛型的使用TypeScript型別泛型
- C# 泛型 引用型別約束 值型別約束C#泛型型別
- Go Internals: Go 反射 vs Java 泛型 vs cpp 模板Go反射Java泛型
- C++ primer 模板與泛型程式設計C++泛型程式設計
- Java泛型知識點:泛型類、泛型介面和泛型方法Java泛型
- Java 泛型,你瞭解型別擦除嗎?Java泛型型別
- 【原創】【自制系列】自制stack型別(泛型)型別泛型
- java中泛型之型別萬用字元(?)Java泛型型別字元
- 泛型作為返回型別的寫法泛型型別
- Java中建立泛型型別的例項Java泛型型別
- 泛型類、泛型方法及泛型應用泛型
- rust trait 關聯型別和泛型的區別RustAI型別泛型
- [譯] Scala 型別的型別(四)型別
- [譯] Scala 型別的型別(二)型別
- [譯] Scala 型別的型別(三)型別
- [譯] Scala 型別的型別(六)型別
- [譯] Scala 型別的型別(五)型別