.net框架中,c#為回調函數提供了委托的類型安全機制,下面是聲明,創建和使用
namespace CSharpDotNet
{
class Set
{
public Set(Int32 numberItems)
{
items = new Object[numberItems];
for (Int32 i = 0; i < numberItems; i++)
items[i] = i;
}
private Object[] items;
public delegate void FeedBack(Object value, Int32 item, Int32 numberItems);
/*public FeedBack:System.MulticastDelegate{
public FeedBack(Object target,Int32 methodPtr);
public virtual void Invoke(Object value, Int32 item, Int32 numberItems);
public virtual IAsyncResult BeginInvoke(Object value, Int32 item, Int32 numberItems,
AsyncCallback callback,Object object);
public virtual IAsyncResult EndInvoke(IAsyncResult result);
}*/
public void ProcessItems(FeedBack feedback)
{
for (Int32 i = 0; i < items.Length; i++)
{
if (feedback != null)
{
feedback(items[i], i + 1, items.Length);
}
}
}
}
class Program
{
static void StaticCallbacks()
{
Set setOfItems = new Set(5);
setOfItems.ProcessItems(new Set.FeedBack(Program.FeedBackToConsole));
}
static void FeedBackToConsole(Object value, Int32 item, Int32 numberItems)
{
Console.WriteLine("{0},{1},{2}", value, item, numberItems);
}
static void InstanceCallbacks()
{
Set setOfItems = new Set(5);
Program p = new Program();
setOfItems.ProcessItems(new Set.FeedBack(p.FeedBackToMsg));
}
private void FeedBackToMsg(Object value, Int32 item, Int32 numberItems)
{
Console.WriteLine("msg");
}
static void Main(string[] args)
{
StaticCallbacks();
InstanceCallbacks();
}
}
}
上例顯示了使用委托如何靜態回調和非靜態回調方法,當聲明
public delegate void FeedBack(Object value, Int32 item, Int32 numberItems);
微軟編譯器為其產生如下定義:
public FeedBack:System.MulticastDelegate{
public FeedBack(Object target,Int32 methodPtr);
public virtual void Invoke(Object value, Int32 item, Int32 numberItems);
public virtual IAsyncResult BeginInvoke(Object value, Int32 item, Int32 numberItems,
AsyncCallback callback,Object object);
public virtual IAsyncResult EndInvoke(IAsyncResult result);
}
因為委托聲明為public,所以會產生public類,可以在任何類定義的地方聲明委托,委托本質是一個類,因為委托繼承System.MulticastDelegate,
所以會繼承其相應字段:
_target,_methodPtr,_prev.
public FeedBack(Object target,Int32 methodPtr);構造函數包含兩個參數,target和methodPtr,一個對象引用和一個指向回調函數的整數,
但是我們構造的時候只是給了Program.FeedBackToConsole這樣的值,其實是編譯器為我們做了工作,它知道我們在構造委托,它會分析源代碼知道我們
引用的是哪個對象和哪個方法
當委托調用的時候feedback(items[i], i + 1, items.Length);實質是feedback.Invoke(items[i], i + 1, items.Length);不過c#不允許
顯示調用該方法,當invoke調用的時候,它使用_target,_methodPtr來指定對象調用的方法,invoke方法的簽名和聲明的委托簽名一致
System.MulticastDelegate System.Delegate,前者繼承與后者,微軟編譯器產生的委托都是繼承與System.MulticastDelegate,但是我們有些時候
會遇到System.Delegate,System.Delegate提供了兩個靜態方法,Combine和Remove,其參數都是Delegate類型,所以我們可以傳遞MulticastDelegate
給它
關于委托的判等
Delegate重寫了Object的Equals方法,如果_target和_methodPtr是否指向同樣的對象和方法,返回true
MulticastDelegate重寫了Delegate的Equals方法,在delegate之上,還要比較_prev
委托鏈
MulticastDelegate的_prev保存了下一個委托的應用,使得多個委托對象可以組成一個鏈表
Delegate定義了三個靜態方法:
public static Delegate Combine(Delegate tail,Delegate head);
public static Delegate Combine(Delegate[] delegateArray);
public static Delegate Remove(Delegate source,Delegate value);
class FeedBack:MulticastDelegate{
public void virtual Invoke(Object value, Int32 item, Int32 numberItems){
if(_prev!=null)_prev.Invoke(value,item,numberItems);
_target.methodPtr(value,item,numberItems);
}
}
可以看出,當委托鏈調用的時候,如果回調函數有返回值,將只保留最后一個委托調用的返回值,而且鏈表尾部的
委托先調用,遞歸調用
c#中重載了-=,+=,可以方便實現委托鏈的操作,其實質是調用了以上三個靜態函數實現,同時為了增加對委托的控制,
MulticastDelegate提供了
public virtual Delegate[] GetInvocationList();
返回委托鏈的數組,可以操控里面的每個委托對象。
(具體請參考Microsoft.Net 框架設計)
posted on 2010-09-29 17:24
小果子 閱讀(325)
評論(0) 編輯 收藏 引用 所屬分類:
.Net