学习《.net框架 程序设计》学习笔记---委托(一)

一.认识委托

      在.net框架中,回调函数任然像在非托管windows编程中一样有用和普遍。但是,.net框架为回调函数提供了一种称为委托(delegate)的类型安全的机制。

      例如:  class Set { private object[] items; public Set(Int32 numItems) { items = new object[numItems]; for (Int32 i = 0; i < numItems; i++) items[i] = i; } ///

/// 定义一个FeedBack委托类型 /// /// /// /// public delegate void FeedBack(object value, Int32 item, Int32 numItems); public void ProcessItems(FeedBack feedback) { for (Int32 item = 0; item < items.Length; item++) { //如果指定有回调函数,则调用它们 if (feedback != null) feedback(items[item], item += 1, items.Length); } } } class App { static void Main() { } static void StaticCallbacks() { Set setOfItems = new Set(5); setOfItems.ProcessItems(null); Console.WriteLine(); setOfItems.ProcessItems(new Set.FeedBack(App.FeedbackToConsole)); Console.WriteLine(); setOfItems.ProcessItems(new Set.FeedBack(App.FeedbackToMsgBox)); Console.WriteLine(); Set.FeedBack fb = null; fb += new Set.FeedBack(App.FeedbackToConsole); fb += new Set.FeedBack(App.FeedbackToMsgBox); setOfItems.ProcessItems(fb); Console.WriteLine(); } static void FeedbackToConsole(object value, Int32 item, Int32 numItems) { Console.WriteLine("Processing item {0} of {1}:{2}",item,numItems,value); } static void FeedbackToMsgBox(object value, Int32 item, Int32 numItems) { MessageBox.Show(string.Format("Processing item {0} of {1}:{2}", item, numItems, value)); } static void InstanceCallbacks() { Set setOfItems = new Set(5); App appobj = new App(); setOfItems.ProcessItems(new Set.FeedBack(appobj.FeedbackToFile)); Console.WriteLine(); } void FeedbackToFile(object value, Int32 item, Int32 numItems) { StreamWriter sw = new StreamWriter("Status", true); sw.WriteLine("Processing item {0} of {1}:{2}", item, numItems, value); sw.Close(); } } class Set { private object[] items; public Set(Int32 numItems) { items = new object[numItems]; for (Int32 i = 0; i < numItems; i++) items[i] = i; } /// /// 定义一个FeedBack委托类型 /// /// /// /// public delegate void FeedBack(object value, Int32 item, Int32 numItems); public void ProcessItems(FeedBack feedback) { for (Int32 item = 0; item < items.Length; item++) { //如果指定有回调函数,则调用它们 if (feedback != null) feedback(items[item], item += 1, items.Length); } } } class App { static void Main() { } static void StaticCallbacks() { Set setOfItems = new Set(5); setOfItems.ProcessItems(null); Console.WriteLine(); setOfItems.ProcessItems(new Set.FeedBack(App.FeedbackToConsole)); Console.WriteLine(); setOfItems.ProcessItems(new Set.FeedBack(App.FeedbackToMsgBox)); Console.WriteLine(); Set.FeedBack fb = null; fb += new Set.FeedBack(App.FeedbackToConsole); fb += new Set.FeedBack(App.FeedbackToMsgBox); setOfItems.ProcessItems(fb); Console.WriteLine(); } static void FeedbackToConsole(object value, Int32 item, Int32 numItems) { Console.WriteLine("Processing item {0} of {1}:{2}",item,numItems,value); } static void FeedbackToMsgBox(object value, Int32 item, Int32 numItems) { MessageBox.Show(string.Format("Processing item {0} of {1}:{2}", item, numItems, value)); } static void InstanceCallbacks() { Set setOfItems = new Set(5); App appobj = new App(); setOfItems.ProcessItems(new Set.FeedBack(appobj.FeedbackToFile)); Console.WriteLine(); } void FeedbackToFile(object value, Int32 item, Int32 numItems) { StreamWriter sw = new StreamWriter("Status", true); sw.WriteLine("Processing item {0} of {1}:{2}", item, numItems, value); sw.Close(); } }

    Set类中定义一个公有委托类型Feedback。委托表示一个回调方法的签名。在本例中,Feedback委托表示一个接受3个参数(一个Objcet和两个Int32),并且返回值为void的回调方法。

   Set类定义一个名为ProcessItems的公有方法。该方法接受一个参数feedback(一个指向Feedback委托对象的引用),然后便利Object数组中的所有元素,并对每一个元素调用有feedback变量所指定的回调方法。传递给回调方法的参数分别为待处理元素值、元素序号、以及数组中 元素的总数。回调方法可以选择任何的方式来处理每个元素。

二.委托揭秘

   从上的例子看,委托好像很容易使用。但是,整个事情并非前面的例子所演示的那样简单。编辑器CLR在后台做了很多工作来影藏问题本身的复杂性。

   当编译器遇到这段代码时,它会产如下面所示的一个完整的定义:

   view plaincopy to clipboardprint?
public class FeedBack : System.MulticasDelegate  
   {  
 
       //构造器  
       public FeedBack(Object target, Int32 methodPtr);  
 
       //下面的方法和源代码中指定的原型一样  
       public void virtual Invoke(Object value, Int32 item, Int32 numItems);  
 
       //下面这两个方法允许我们对委托进行异步回调  
       public virtual IAsyncResult BeginInvoke(Object value, Int32 item, Int32 numItems,AsyncCallback callback,Object object );  
       public virtual void EndInvoke(IAsyncResult result);  
   } 
 public class FeedBack : System.MulticasDelegate
    {

        //构造器
        public FeedBack(Object target, Int32 methodPtr);

        //下面的方法和源代码中指定的原型一样
        public void virtual Invoke(Object value, Int32 item, Int32 numItems);

        //下面这两个方法允许我们对委托进行异步回调
        public virtual IAsyncResult BeginInvoke(Object value, Int32 item, Int32 numItems,AsyncCallback callback,Object object );
        public virtual void EndInvoke(IAsyncResult result);
    }

     编译器定义了一个名为FeedBack的类,其继承自.NET框架类库(FCL)中定义的System.MulticasDelegate。由于我在源代码中将FeedBack委托类型声明为Pulice,所以编译器产生的FeedBack为一个公共类。如果我们在源码中将其声明为其他修饰符,那么编译器将产生同样的类。委托可以定义在一个类中,也可以定义在一个全局的范围内。因为委托本身就是类,一个可以在哪里定义,一个委托就可以在哪里定义。

      注意所有委托都有一个构造器,并且该构造器接受两个参数:一个对象引用和一个指向回调方法的整数。

      在编译器编编译时:它会通过分析源代码来确定我们引用的事那个对象和方法。其中的对象引用会被传递给target参数,一个特殊的标识方法的Int32值会被传递methodPrt参数。对于静态方法而言,null会被传递给target。在构造器内部,这两个参数会被保存在相应的似有字段中。

      每个委托对象实际上是对方法及其调用是操作的对象的一个封装。MuliticastDlegate类定义了两个只读公有实例属性:Target和Method。给定一个委托对象的引用,我们可以查询这些属性。Target属性返回一个方法回调是操作的对象引用。如果是静态方法,Target将返会null。Method属性返回一个标识回调方法的System.Relfection.MethodInfod对象。

       例如

       我们查看一个委托对象是否引用着一个特定类型的实例方法:

       Boolean DelegateRefersToInstanceMethodOfType(MutivastDelegate d,Type type)

{

  return (d.Target!=null&&d.Target.GetType()==type);

}

     我们可以查看回调方法是否有着一个特定的名称

  Boolean DelegateRefersToMehtodOfName(MutivastDelegate d,string methodName)

{

return (d.Method.Name==methodName);
}

    在Set类中ProcessItems方法中:

    注释下面就是调用回调方法的代码,这里实际上没有什么feedback函数。编译器在编译时知道feedback是一个指向委托对象的变量,所以它会产生代码来调用委托对象的Invoke方法。

    他将源代码中的

                       feedback(items[item], item += 1, items.Length);
编译为:

                    feedback.Invoke(items[item], item += 1, items.Length);

但是在c#中不允许我们现实调用Invoke方法,将会报:“error CS1533 Invoke无法直接在委托中调用”。

编译在定义Feedback类时定义Invoke方法,它的签名和Feedback委托的签名是相匹配的。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zyxfcb1520/archive/2011/06/21/6559948.aspx

你可能感兴趣的:(.Net)