zoukankan      html  css  js  c++  java
  • [C#] C# 知识回顾

    C# 知识回顾 - 委托 delegate

    【博主】反骨仔    【原文】http://www.cnblogs.com/liqingwen/p/6031892.html

    目录

    What's 委托

      delegate 一种自定义的引用类型,它包含了特定的参数列表和返回类型

      使用委托时,只需要对应的方法的签名和返回类型兼容即可,无论是实例方法,抑或是静态方法。通过调用委托的实例就相当于调用方法本身,因为委托存储的是一个方法列表,调用委托的实例就相当于依次调用方法列表的内容。委托它将方法作为参数进行传递给了其它方法,我们常用的事件处理程序就是通过委托调用的方法,也是一种观察者模式的体现。

      下面的示例演示了一个委托声明:

    public delegate int Del(int x, int y);

      

      使用委托的要求是:方法签名与返回类型兼容。可以是静态方法,也可以是实例方法。  

     

      【备注】方法的签名不包括返回值

    委托的特点

    • 类型安全,类似于 C 和 C++ 中的函数指针。

    • 可将方法作为参数进行传递。

    • 可用于定义回调方法。

    • 委托可以链接在一起;例如,可以对一个事件调用多个方法。

    • 方法不必与委托类型完全匹配。

    使用委托

      委托,一种类型,它是安全的,自定义的,委托的名称就决定了这个委托是什么类型。

        //该委托可以封装 “,参数类型 string,返回类型 void” 的方法 
        public delegate void MyDel(string message);

      委托的实例对象通常使用两种方式进行构建,直接使用类的方法名,或者使用 Lambda 表达式,当然匿名方法也可以。

      在调用委托的时刻,我们将传递到委托的参数会继续传递到委托列表的方法中。如果委托列表中包含返回值的话,会将最后一个返回值返回给调用方。也就是该委托对象调用完毕的返回值。

     1     //该委托名为 MyDel,可以封装 “参数类型 string,返回值类型 void” 的方法 
     2     public delegate void MyDel(string message);
     3 
     4     class Program
     5     {
     6         static void Main(string[] args)
     7         {
     8             //实例化委托
     9             MyDel del = Print;
    10             //调用委托
    11             del("Hi");
    12 
    13             Console.Read();
    14         }
    15 
    16         /// <summary>
    17         /// 打印文本
    18         /// </summary>
    19         /// <remarks>这是一个可用于 MyDel 委托的方法</remarks>
    20         /// <param name="message"></param>
    21         private static void Print(string message)
    22         {
    23             Console.WriteLine(message);
    24         }
    25     }

      委托的关键字是 delegate,它派生自 Delegate 类,也是 sealed,即密封类,不能作为基类再继续派生。

      异步回调:允许以方法的形式作为参数形式进行传递,并在稍后进行该委托的调用。通过这个形式使用的委托,调用方不需要知道方法的具体实现,只是简单的把它当做一个功能即可,这类似接口的封装。

     
      简单的异步回调方法演示:
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             MyDel del = Print;
     6             CallbackMethod(100, 150, del);  //将委托传递到 CallbackMethod 方法
     7 
     8             Console.Read();
     9         }
    10 
    11         /// <summary>
    12         /// 回调方法
    13         /// </summary>
    14         /// <param name="m"></param>
    15         /// <param name="n"></param>
    16         /// <param name="del"></param>
    17         private static void CallbackMethod(int m, int n, MyDel del)
    18         {
    19             del((m + n).ToString());
    20         }
    21 
    22         private static void Print(string message)
    23         {
    24             Console.WriteLine(message);
    25         }
    26     }

      在这里的 CallbackMethod 作用是,调用委托,因为它包含的是 Print() 方法的调用,所以只需要传递对应的 string 类型作为参数即可。

      我们在创建委托的时候,你可以选择使用的是实例方法或者是静态方法。当你使用的是实例方法时,该委托对象会同时引用该实例的对象及它的方法。委托并不关心应用引用对象的类型,它关心的是,方法签名和返回值兼容,即可。不过,如果你创建委托对象包含的是静态方法的时候,它是只引用该方法的。

      使用 += 可以把多个方法添加到一个委托对象的调用列表中,调用一次委托,相当于一次性调用一堆方法。

     1     //该委托可以封装 “名 MyDel,参数类型 string,返回值类型 void” 的方法 
     2     public delegate void MyDel(string message);
     3 
     4     class MyClass
     5     {
     6         public void Print1(string message)
     7         {
     8             Console.WriteLine($"{message} - {nameof(Print1)}");
     9         }
    10 
    11         public void Print2(string message)
    12         {
    13             Console.WriteLine($"{message} - {nameof(Print2)}");
    14         }
    15     }
    16 
    17     class Program
    18     {
    19         static void Main(string[] args)
    20         {
    21             var myClass = new MyClass();
    22             MyDel del1 = myClass.Print1;
    23             MyDel del2 = myClass.Print2;
    24             MyDel del3 = Print;
    25 
    26             var del = del1 + del2;
    27             del += del3;    //这里使用 +=
    28             del("Hi!");
    29 
    30             Console.Read();
    31         }
    32 
    33         private static void Print(string message)
    34         {
    35             Console.WriteLine($"{message} - {nameof(Print)}");
    36         }
    37     }

       委托对象 del,他内部存储的是一个包含三个方法的调用列表(Print1、Print2 和 Print),在你调用 del 对象时,调用列表中的方法会依次调用。

      

      多播委托:一个委托对象调用多个方法,使用 +=。

      若要从委托对象的调用列表中移除方法,需要使用 -=。

     1         static void Main(string[] args)
     2         {
     3             var myClass = new MyClass();
     4             MyDel del1 = myClass.Print1;
     5             MyDel del2 = myClass.Print2;
     6             MyDel del3 = Print;
     7 
     8             var del = del1 + del2;
     9             del += del3;    //使用 +=
    10             del("Hi!");
    11 
    12             Console.WriteLine("======分割线======");
    13 
    14             del -= del2;    //使用 -=
    15             del("Hi!");
    16 
    17             Console.Read();
    18         }

      你也可以编写一些方法获取调用列表中方法的数量:

     1         static void Main(string[] args)
     2         {
     3             var myClass = new MyClass();
     4             MyDel del1 = myClass.Print1;
     5             MyDel del2 = myClass.Print2;
     6             MyDel del3 = Print;
     7 
     8             var del = del1 + del2;
     9             del += del3;    //使用 +=
    10             //del("Hi!");
    11 
    12             var count = del.GetInvocationList().Length; //获取委托调用列表中方法的数量
    13             Console.WriteLine(count);
    14 
    15             Console.WriteLine("======分割线======");
    16 
    17             del -= del2;    //使用 -=
    18             //del("Hi!");
    19 
    20             count = del.GetInvocationList().Length; //获取委托调用列表中方法的数量
    21             Console.WriteLine(count);
    22 
    23             Console.Read();
    24         }

      多播委托派生自 MulticastDelegate,也是继承自 Delegate的,常用于事件处理中。

    传送门

      《C# 知识回顾 - 序列化

      《C# 知识回顾 - 表达式树 Expression Trees

     


    【参考】https://msdn.microsoft.com/zh-cn/library/windows/apps/ms173171(v=vs.120).aspx

    【参考】微软官方文档

  • 相关阅读:
    20年美亚杯WRITE UP
    博客搬迁
    前端工程化1-模块
    移动端(h5)工具函数--视口适配(viewport)
    Understanding ES6 Modules(译)
    手写http请求并发、重试、超时函数
    两道编程题引发的思考
    前端基础走查(六):异步任务和事件循环
    vue 本地图片批量下载以及压缩成zip文件下载
    mybatis generator逆向工程
  • 原文地址:https://www.cnblogs.com/liqingwen/p/6031892.html
Copyright © 2011-2022 走看看