.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
小果子 阅读(316)
评论(0) 编辑 收藏 引用 所属分类:
.Net