zoukankan      html  css  js  c++  java
  • 委托、匿名函数、Lambda表达式和事件的学习

    委托:

    还记得C++里的函数指针么?大家可以点击这里查看一下以前的笔记。C#的委托和C++中的函数指针效果一致。

    当我们需要将函数作为对象进行传递和使用时就需要用到委托。

    下面我们看一个例子:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             //声明委托的实例
    14             ProcessDelegate pd;
    15 
    16             //指定委托的函数
    17             pd = Multiply;
    18             Console.WriteLine(pd(12, 6));
    19 
    20             //指定委托的函数
    21             pd = Divide;
    22             Console.WriteLine(pd(12, 6));
    23 
    24             //将委托作为参数传递
    25             Func1(pd);
    26             //将函数直接作为参数传递
    27             Func1(Multiply);
    28 
    29             Console.ReadKey();
    30         }
    31 
    32         /// <summary>
    33         /// 声明一个委托.
    34         /// </summary>
    35         delegate double ProcessDelegate(double param1, double param2);
    36 
    37         static double Multiply(double param1, double param2)
    38         {
    39             return param1 * param2;
    40         }
    41 
    42         static double Divide(double param1, double param2)
    43         {
    44             return param1 / param2;
    45         }
    46 
    47         /// <summary>
    48         /// 参数为委托类型的函数.
    49         /// </summary>
    50         static void Func1(ProcessDelegate pd)
    51         {
    52             Console.WriteLine(pd(55, 11));
    53         }
    54     }
    55 }

    运行的结果如下:

    1 72
    2 2
    3 5
    4 605

    初始化定义和委托推断:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         delegate string GetAString();
    12 
    13         static void Main(string[] args)
    14         {
    15             int x = 40;
    16             //这里我称为初始化定义, 注意不能写成 x.ToString()
    17             GetAString method = new GetAString(x.ToString);
    18             Console.WriteLine(method());
    19 
    20             x = 123;
    21             //通过委托推断可以简化代码编写, 注意不能写成 x.ToString()
    22             GetAString method2 = x.ToString;
    23             Console.WriteLine(method2());
    24 
    25             Console.ReadKey();
    26         }
    27     }
    28 }

    多播委托:

    多播委托支持“+”“-”操作符,可以添加多个方法到同一个委托中,当委托被执行时,并不会按照添加的顺序依次调用函数,调用顺序是无法保证的。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         delegate void DoubleOp(double value);
    12 
    13         public static void Func1(double value)
    14         {
    15             double result = value * 2;
    16             Console.WriteLine("Func1 value: {0}, result: {1}", value, result);
    17         }
    18 
    19         public static void Func2(double value)
    20         {
    21             double result = value * value;
    22             Console.WriteLine("Func2 value: {0}, result: {1}", value, result);
    23         }
    24 
    25         static void Main(string[] args)
    26         {
    27             DoubleOp op = Func1;
    28             //添加一个方法
    29             op += Func2;
    30 
    31             op(1);
    32             Console.WriteLine();
    33             op(2);
    34             Console.WriteLine();
    35 
    36             //去掉一个方法
    37             op -= Func1;
    38 
    39             op(3);
    40 
    41             Console.ReadKey();
    42         }
    43     }
    44 }

    下面是运行的结果:

    1 Func1 value: 1, result: 2
    2 Func2 value: 1, result: 1
    3 
    4 Func1 value: 2, result: 4
    5 Func2 value: 2, result: 4
    6 
    7 Func2 value: 3, result: 9

    匿名函数:

    使用时直接进行定义的函数。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         delegate string GetString(float num);
    12 
    13         static void Main(string[] args)
    14         {
    15             //定义匿名函数
    16             GetString m = delegate(float num)
    17             {
    18                 return num.ToString();
    19             };
    20             Func(m, 10.5f);
    21 
    22             //直接传递匿名函数
    23             Func(delegate(float num)
    24             {
    25                 num *= 2.0f;
    26                 return num.ToString();
    27             }, 20.5f);
    28 
    29             Console.ReadKey();
    30         }
    31 
    32         static void Func(GetString method, float num)
    33         {
    34             Console.WriteLine("Func: " + method(num));
    35         }
    36     }
    37 }

    下面是运行的结果:

    1 Func: 10.5
    2 Func: 41

    Lambda表达式:

    Lambda表达式可以用来简化匿名函数的写法,如果把上面的示例改为Lambda表达试则如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         delegate string GetString(float num);
    12 
    13         static void Main(string[] args)
    14         {
    15             //使用表达式进行简写
    16             GetString m = num =>
    17                 {
    18                     return num.ToString();
    19                 };
    20             Func(m, 10.5f);
    21 
    22             //直接传递表达试
    23             Func(num =>
    24                 {
    25                     num *= 2.0f;
    26                     return num.ToString();
    27                 }, 20.5f);
    28 
    29             Console.ReadKey();
    30         }
    31 
    32         static void Func(GetString method, float num)
    33         {
    34             Console.WriteLine("Func: " + method(num));
    35         }
    36     }
    37 }

    Lambda表达式可以去掉函数参数的类型,因为该类型编译器可以从上下文中获得。如果存在多个参数则需要添加括号,如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         delegate string GetString(float num, int num2);
    12 
    13         static void Main(string[] args)
    14         {
    15             //使用表达式进行简写
    16             GetString m = (num, num2) =>
    17                 {
    18                     return num.ToString() + "," + num2.ToString();
    19                 };
    20             Func(m, 10.5f, 100);
    21 
    22             //直接传递表达试
    23             Func((num, num2) =>
    24                 {
    25                     num *= 2.0f;
    26                     num += num2;
    27                     return num.ToString();
    28                 }, 20.5f, 200);
    29 
    30             Console.ReadKey();
    31         }
    32 
    33         static void Func(GetString method, float num, int num2)
    34         {
    35             Console.WriteLine("Func: " + method(num, num2));
    36         }
    37     }
    38 }

    下面是运行的结果:

    1 Func: 10.5,100
    2 Func: 241

    如果代码仅有一行还可以省略return和大括号,如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         delegate string GetString(float num, int num2);
    12 
    13         static void Main(string[] args)
    14         {
    15             //使用表达式进行简写
    16             GetString m = (num, num2) => num.ToString() + "," + num2.ToString();
    17             Func(m, 10.5f, 100);
    18 
    19             //直接传递表达式
    20             Func((num, num2) => num.ToString() + "," + num2.ToString(), 20.5f, 200);
    21 
    22             Console.ReadKey();
    23         }
    24 
    25         static void Func(GetString method, float num, int num2)
    26         {
    27             Console.WriteLine("Func: " + method(num, num2));
    28         }
    29     }
    30 }

    下面是运行的结果:

    1 Func: 10.5,100
    2 Func: 20.5,200

    这里引入了一个新的知识点协变和抗变,大家可以自行搜索,或者查看协变和抗变的文章点击这里

    事件:

    C#里的事件使用event关键字定义,无需实例化就可以使用,可以将其看做一个特殊的委托对象,下面我们看看一个例子。

    EventDispatcher.cs(用来定义和发送特定事件的类):

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     /// <summary>
    10     /// 事件发送类.
    11     /// </summary>
    12     class EventDispatcher
    13     {
    14         /// <summary>
    15         /// 定义特定的事件委托, 注意不要有返回值.
    16         /// </summary>
    17         /// <param name="sender">发送者.</param>
    18         /// <param name="args">附带的参数.</param>
    19         public delegate void MyEventHandler(object sender, MyEventArgs args);
    20 
    21         /// <summary>
    22         /// 事件对象, 所有的回调都可以添加到该对象上, 不需要实例化就能使用.
    23         /// </summary>
    24         public event MyEventHandler onCustom;
    25 
    26         /// <summary>
    27         /// 构造函数.
    28         /// </summary>
    29         public EventDispatcher()
    30         {
    31         }
    32 
    33         /// <summary>
    34         /// 发送一个自定义事件.
    35         /// </summary>
    36         /// <param name="data">数据.</param>
    37         public void dispatchCustom(String data)
    38         {
    39             onCustom(this, new MyEventArgs(data));
    40         }
    41     }
    42 
    43     /// <summary>
    44     /// 自定义事件参数类.
    45     /// </summary>
    46     class MyEventArgs : EventArgs
    47     {
    48         public String data;
    49 
    50         public MyEventArgs(String data)
    51         {
    52             this.data = data;
    53         }
    54     }
    55 }

    Program.cs(主程序,测试类):

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             new Program();
    14 
    15             Console.ReadKey();
    16         }
    17 
    18         public Program()
    19         {
    20             EventDispatcher ed = new EventDispatcher();
    21 
    22             //第一种方式
    23             EventDispatcher.MyEventHandler meh = new EventDispatcher.MyEventHandler(CustomHandler);
    24             ed.onCustom += meh;
    25             ed.dispatchCustom("Hello One!");
    26             ed.onCustom -= meh;
    27 
    28             //第二种方式
    29             ed.onCustom += new EventDispatcher.MyEventHandler(CustomHandler);
    30             ed.dispatchCustom("Hello Two!");
    31             //下面两种方式都可以删除注册的事件处理函数
    32             ed.onCustom -= new EventDispatcher.MyEventHandler(CustomHandler);
    33             //ed.onCustom -= CustomHandler;
    34 
    35             //简写方式
    36             ed.onCustom += CustomHandler;
    37             ed.dispatchCustom("Hello Three!");
    38             ed.onCustom -= CustomHandler;
    39 
    40             //匿名函数写法
    41             ed.onCustom += delegate(object sender, MyEventArgs args)
    42                 {
    43                     Console.WriteLine("Event Handler (delegate) : " + args.data);
    44                 };
    45             ed.dispatchCustom("Hello Four!");
    46 
    47             //Lambda 写法
    48             ed.onCustom += (sender, args) =>
    49                 {
    50                     Console.WriteLine("Event Handler (lambda) : " + args.data);
    51                 };
    52             ed.dispatchCustom("Hello Five!");
    53 
    54             //简写 Lambda
    55             ed.onCustom += (sender, args) => Console.WriteLine("Event Handler (lambda) : " + args.data);
    56             ed.dispatchCustom("Hello six!");
    57         }
    58 
    59         private void CustomHandler(object sender, MyEventArgs args)
    60         {
    61             Console.WriteLine("Event Handler : " + args.data);
    62         }
    63     }
    64 }

    下面是程序运行的结果:

    1 Event Handler : Hello One!
    2 Event Handler : Hello Two!
    3 Event Handler : Hello Three!
    4 Event Handler (delegate) : Hello Four!
    5 Event Handler (delegate) : Hello Five!
    6 Event Handler (lambda) : Hello Five!
    7 Event Handler (delegate) : Hello six!
    8 Event Handler (lambda) : Hello six!
    9 Event Handler (lambda) : Hello six!
  • 相关阅读:
    python学习笔记Day3
    python学习笔记Day2
    IIS7.5部署除静态页面外都是404的解决方案
    CommandBehavior.CloseConnection有何作用
    没事别老待在家里
    冻结表格行列的思路
    如何构建逻辑清晰的可拖拽树的数据结构
    “仅次于20年前的最好的时间是现在“
    java的静态代理和2种动态代理(未完,待续)
    i++和++i
  • 原文地址:https://www.cnblogs.com/hammerc/p/4398032.html
Copyright © 2011-2022 走看看