[譯]分辨差別 -- 第一部分: 泛型不是模板

iDotNetSpace發表於2009-10-13

譯自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(T t)

    {

        ReallyDoIt(t);

    }

    private static void ReallyDoIt(string s)

    {

        System.Console.WriteLine("string");

    }

    private static void ReallyDoIt(T t)

    {

        System.Console.WriteLine("everything else");

    }

}

當你呼叫C.DoIt會發生什麼呢?很多人希望列印出“string”, 然而不管T是什麼,事實上總是列印出“everything else”。

C#語言標準說當你需要面臨選擇呼叫ReallyDoIt(string)或是ReallyDoIt(string)的時候,也就是說在需要從兩個相同簽名方法選擇, 其中包含一個是泛型方法的時候,我們會選擇非泛型的方法而不是泛型的方法。但在這裡我們為什麼不這麼做呢?

因為那不是標準所說的選擇。如果你說要呼叫ReallyDoIt("hello world");

那麼我們會選擇非泛型的版本。但是你並不是把編譯器所知道的string型別進行引數傳遞。你只是傳遞了型別T,一個沒有約束的型別引數,所以它可以是任何型別。所以由於過載決議的演算法,有沒有一個方法能接收任何型別作為引數呢?回答是有。

這個C#裡泛型的例子並不像C++裡面的模板。你可以把模板想象成一個奢華的搜尋替代的機制。當你說你要在模板中呼叫DoIt, 編譯器會概念性地搜尋出所有用到的“T”,再把它們替換成“string” ,接著再編譯原始碼。過載決議用替代的已知型別引數來執行,生成的程式碼也反映了過載決的結果。

泛型可不是這麼工作的。泛型是這樣的,好吧,一般的。我們只做一次過載決議然後固定了結果。當任何程式從一個完全不同的程式集用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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章