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

    【参考】微软官方文档

  • 相关阅读:
    LeetCode 88. Merge Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 581. Shortest Unsorted Continuous Subarray
    LeetCode 20. Valid Parentheses
    LeetCode 53. Maximum Subarray
    LeetCode 461. Hamming Distance
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 976. Largest Perimeter Triangle
    LeetCode 1295. Find Numbers with Even Number of Digits
    如何自学并且系统学习计算机网络?(知乎问答)
  • 原文地址:https://www.cnblogs.com/liqingwen/p/6031892.html
Copyright © 2011-2022 走看看