2013年7月26日 星期五

interface 的兩三事


CLR 要求 interface 裡面的所有 methods/properties/indexers/delegates/events  都必須是 virtual.
因此, 下面幾行程式:

class Base : IDisposable, ICloneable {
    public Object Clone() { ...; }
    public virtual void Dispose() { ...; }
}

其實會被 C# Compiler 偷偷改成下面這樣:

class Base : IDisposable, ICloneable {
    public virtual sealed Object Clone() { ...; }
    public virtual void Dispose() { ...; }
}

-------------------------------------------------------
當一個 type 被 load 進 CLR, CLR 會在記憶體內建立一個 type object, 用來記錄該 type 的資訊, 其中也包含 method table. 

method table 內包含:
1. new methods introduced by the type
2. any virtual methods inherited by the type

比如說:
class SimpleType : IDisposable {
    public void Dispose() { ...; }
}

SimpleType 的 type object 內的 method table 會含有:
1. 所有 Object 定義的 virtual methods
2. IDispose 定義的 virtual method - void Dispose();
3. SimpleType 自建的新 function - void DIspose();

以上的 2 和 3 是兩個欄位, 並不是我寫錯. 當 C# Compiler 發現 3 和 2 其實可以參考同一個 method 時, 會將他們填入相同的值. 參考下面的 code

SimpleType st = new SimpleType();
st.Dispose(); // 呼叫的是 3
((IDisposable)st).Dispose(); // 呼叫的是 2

以下的語法叫做 Explicit Interface Method Implementation (EIMI), 可以讓上述的 2 與 3 填入不同的 method.

class SimpleType : IDisposable {
    public void Dispose() { // 填入欄位 3
        Console.WriteLine("SimpleType.Dispose");
    }
    void IDisposable.Dispose() { // 填入欄位 2
        Console.WriteLine("IDispose.Dispose");
    }
}

請注意一件很重要的差別!!! Dispose() 其實是一個全新的 function, 跟 IDisposable 一點關係也沒有, 只是恰巧也叫做 void Dispose() 而已. IDisposable.Dispose() 才是真正實作 IDisposable 的 method. 他的修飾詞會被強迫偷偷的設定為 private virtual sealed. 只有將 SimpleType 明確轉型為 IDisposable 時才呼叫得到.

出處: CLR via C# 4Ed Chapter 13

沒有留言:

張貼留言