開始聊聊C#泛型和委託(一)

來源:互聯網
上載者:User

上篇文章簡單的談了談C#編譯器和JIT編譯器,本來想接著寫類型,對象,線程棧和託管堆在運行時的相互關係的,可惜講解這部分採用畫圖的方式比較好,所以就先跳過了。

在JAVA中,泛型只被JAVA編譯器支援,並不被JVM所支援,也就是說沒有定義新的位元組碼來表示泛型型別,自然在JVM裡面也不會有新的指令來支援新的位元組碼。類比到.NET來說,也就是被C#編譯器支援而不被CLR所支援。這樣就產生了很多有趣的問題。我們都知道我們的代碼都要經過編譯器的翻譯改動,JAVA中的泛型就是JAVA編譯器採用類型擦除的方式來實現泛型的。定義的泛型型別,都自動提供了一個相應的原始類型(raw type)原始類型的名字就是刪去型別參數後的泛型名,擦出掉類型變數,並替換為限定類型(無限定的變數用Object),可以看做是文法糖吧。比如:

public class MyHashMap<TKey, TValue> {    private HashMap<TKey, TValue> m_map = new HashMap<TKey, TValue>();        public TValue get(TKey key) {        return this.m_map.get(key);    }        public void put(TKey key, TValue value) {        this.m_map.put(key, value);    }    public static void main(String[] args) {        MyHashMap<String, Integer> map = new MyHashMap<String, Integer>();        map.put("Hello", 5);        int i = map.get("Hello");    }    }

編譯成位元組碼後,就成了下面這個樣子(這裡還用JAVA代碼來表示)

public class MyHashMap {
private HashMap m_map = new HashMap();

public Object get(Object key) {
return this.m_map.get(key);
}

public void put(Object key, Object value) {
this.m_map.put(key, value);
}

public static void main(String[] args) {
MyHashMap map = new MyHashMap();
map.put("Hello", 5);
int i = (Integer)map.get("Hello");
}
}

好吧,看到Object,我承認我又想起裝箱了,可以看出Java中的泛型沒有解決裝箱問題。

由於JVM並不知道泛型型別,所以JAVA中就是以JAVA編譯器的文法糖的形式來表現的。當初我剛接觸JAVA的時候,的確會被下面幾種錯誤弄得很困惑。

public class MyClass<SomeType> {    public static void myMethod(Object item) {        if (item instanceof SomeType) { // 報錯            ...        }        SomeType st = new SomeType(); // 報錯        SomeType[] myArray = new SomeType[10]; // 報錯    }}

在這裡我們可以想一下,到底怎麼樣才算真正的支援泛型呢?在.NET中,最終是由CLR根據中繼資料來執行IL代碼,因此,可以很容易理解:

1.IL中一定會有一個新指令來識別“型別參數”。

2.我們知道類型和方法的定義在中繼資料表中都會有相應的表示,因此為了支援泛型,中繼資料的格式也會有所改動。

3.修改JIT編譯器來執行新的IL指令。

也就是說,泛型型別定義能夠完整的編譯為MSIL類型。

泛型型別的運行大概的流程如下:

C#編譯器產生IL和中繼資料,表示泛型類定義,JIT編譯器則會把泛型型別定義與一系列的型別參數組合起來。

具體點來說,IL為初始化某個泛型型別的執行個體預留了預留位置,JIT編譯器會在啟動並執行時候,產生機器代碼的時候“補全定義”。JIT把相應的IL代碼編譯成X86指令,同時最佳化。最佳化什麼內容了呢?比如,在型別參數是參考型別的時候,就能使用相同的機器代碼來表示。為啥是參考型別而不是實值型別呢?因為參考型別基本上都是指標,本質上來講結構都是一樣的。

這裡又要談一下類載入。JIT不是在某個類載入時就為其產生完整的X86指令,而是僅在類中的每個方法被第一次調用的時候才開始編譯的。(我現在覺得應該先講講類型,對象,線程棧和託管堆在運行時的相互關係比較好)。這樣,就會先在IL代碼上執行一個預留位置替換步驟,替換成具體類型,隨後再像普通類一樣按需編譯。

好吧,你可以看出,在執行之前預留位置被替換成具體類型了,因此泛型的匹配度是相當高的。應該說就是精確匹配。這個會影響什麼地方呢?在方法重載的時候就會有體現了。對於一個派生於MyBase的對象來說,WriteMEsaage<T>(T obj)要比WriteMEsaage(MyBase
obj)在重載匹配上更優先。因為通過將T替換成MyDerived編譯器就可以完成一次“精確匹配”,而WriteMEsaage(MyBase obj)則還需要一次隱式轉換。於是泛型方法更有優勢,除非在調用時進行顯式類型轉換。下面用代碼說明:

public class MyBase{} public class MyDerived : MyBase{    #region IMessageWriter Members    void IMessageWriter.WriteMessage()    {        Console.WriteLine("Inside MyDerived.WriteMessage");    }    #endregion} class Program{    static void WriteMessage(MyBase b)    {        Console.WriteLine("Inside WriteMessage(MyBase)");    }    static void WriteMessage<T>(T obj)    {        Console.Write("Inside WriteMessage<T>(T):  ");        Console.WriteLine(obj.ToString());    }    static void Main(string[] args)    {        MyDerived d = new MyDerived();        Console.WriteLine("Calling Program.WriteMessage");        WriteMessage(d); //讓編譯器推斷使用哪個匹配方法        Console.WriteLine();        Console.WriteLine("Cast to base object");        WriteMessage((MyBase)d);        Console.WriteLine();    }}

因此當你想支援某一類及其所有衍生類別時,基於基類建立泛型並不是最好的選擇。同樣的,基於介面也是如此。

那麼我想針對,這時就需要通過運行時來判斷了,當然,這並不是最好的解決方案,雖然對調用者屏蔽了具體的實現,但同時會帶運行時檢查的開銷。

Static void WriteMessage<T>(T obj){         If(obje is MyBase){                  WriteMessage(obj as MyBase);  //顯式類型轉換         }else {                  Conslole.Write(“Invoke WriteMessage<T>”)         }}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.