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