xiaoguozi's Blog
Pay it forword - 我并不觉的自豪,我所尝试的事情都失败了······习惯原本生活的人不容易改变,就算现状很糟,他们也很难改变,在过程中,他们还是放弃了······他们一放弃,大家就都是输家······让爱传出去,很困难,也无法预料,人们需要更细心的观察别人,要随时注意才能保护别人,因为他们未必知道自己要什么·····
.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

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理