2009-02-09 25 views
7

代表們如何在c#後臺工作以及如何有效地使用它們?編輯:我知道他們如何在表面上工作(他們基本上是函數指針,並允許使用他們的地址調用某些簽名的回調方法)。我需要知道的是CLR如何在內部實現它們。定義委託時以及何時使用委託對象調用回調方法時幕後會發生什麼?代表如何工作(在後臺)?

回答

4

問題的第一部分相對比較簡單:代表存儲函數指針列表。如果您調用委託,它將調用該內部列表中的所有函數指針。添加和刪​​除接收器(通過Delegate.CombineDelegate.Remove)相當於添加到該列表和從列表中刪除。

有關更多底層信息,請參閱ECMA-335(CLI標準),第II.14.5節(方法指針)和II.14.6(代表)。特別要注意的是,委託由一個實例指針(類型爲System.Object)和一個方法指針(類型爲System.IntPtr)組成。方法指針可以通過ldftnldvirtftn(用於虛擬函數調用)指令獲得(在CIL中)。

這兩條信息標識任何方法。

它們如何有效使用?

你是什麼意思?你知道事件還是你的問題更專業?

+0

真的嗎?他們存儲指針?我的印象是事件的確如此,而且代表們有點像強類型的函數類型。 (但我可能會把事情弄混淆。) – scraimer 2009-02-09 09:17:41

5

重效率 - 目前尚不清楚你的意思,但可以用達到的效率,避免昂貴的反射。例如,通過使用Delegate.CreateDelegate來創建(鍵入)預先檢查的動態/查找方法委託,而不是使用(較慢)MethodInfo.Invoke

一個簡單的例子(訪問一個類型的靜態T Parse(string)模式),見下文。請注意,它只使用反射一次(每種類型),而不是很多次。這應該在性能反射或典型TypeConverter用法:

using System; 
using System.Reflection; 
static class Program { // formatted for space 
    static void Main() { 
     // do this in a loop to see benefit... 
     int i = Test<int>.Parse("123"); 
     float f = Test<float>.Parse("123.45"); 
    } 
} 
static class Test<T> { 
    public static T Parse(string text) { return parse(text); } 
    static readonly Func<string, T> parse; 
    static Test() { 
     try { 
      MethodInfo method = typeof(T).GetMethod("Parse", 
       BindingFlags.Public | BindingFlags.Static, 
       null, new Type[] { typeof(string) }, null); 
      parse = (Func<string, T>) Delegate.CreateDelegate(
       typeof(Func<string, T>), method); 
     } catch (Exception ex) { 
      string msg = ex.Message; 
      parse = delegate { throw new NotSupportedException(msg); }; 
     } 
    } 
} 
3

代表在C#是方法指針的列表。即它們存儲對代碼的引用,並且可以通過指針調用這些方法。這在很多情況下很有用。常見的例子是代理用來實現發佈者/訂閱者模式的事件處理程序。

1

當你創建一個委託時,C#編譯器會生成一個完整的類。 這個類包含了一個函數引用列表,正如Konrad所說的。 關於委託的好處是它們爲您提供了簡單的方法,以通知回調異步執行任務。這意味着您可以在後臺操作完成時收到通知。 線程池不提供此功能。 代表是一個廣泛的話題,我發現傑夫裏希特(通過C#的CLR)和Albahari(C#3)書籍提供了特別的幫助。

0

C#委託是封裝對象和方法指針的引用的對象(檢查System.Delegate類)。 它們也可以具有對象的空引用來表示對靜態方法的調用。

使用參數調用委託時,委託會使用指定的參數調用引用對象上的引用方法。

編譯的委託Invoke方法是直接由運行時處理(如用反射可見):

[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)] 
public virtual void Invoke(T obj); 

運行時使用所有信息internaly編譯一個標準方法調用來引用方法。

4

當你定義委託

internal delegate void Feedback(Int32 value); 

編譯器實際上定義了一個完整的類,看起來像這樣的東西 :

internal class Feedback : System.MulticastDelegate { 
    // Constructor 
    public Feedback(Object object, IntPtr method); 

    // Method with same prototype as specified by the source code 
    public virtual void Invoke(Int32 value); 

    // Methods allowing the callback to be called asynchronously 
    public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object object); 

    public virtual void EndInvoke(IAsyncResult result); 
} 

來源:Jeffrey Richter - CLR via C#,第17章