c# 委托认识

c# 委托认识
.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 框架设计)


你可能感兴趣的:(c# 委托认识)