• 【读书笔记】C#高级编程 第八章 委托、lambda表达式和事件


    (一)引用方法

    委托是寻址方法的.NET版本。委托是类型安全的类,它定义了返回类型和参数的类型。委托不仅包含对方法的引用,也可以包含对多个方法的引用。

    Lambda表达式与委托直接相关。当参数是委托类型时,就可以使用lambda表达式实现委托引用的方法。

    (二)委托

    当要把方法传递给其它方法时,需要使用委托。委托是一种特殊类型的对象,其特殊之处在于,我们以前定义的所有对象都包含数据,而委托包含的只是一个或多个方法的地址。

    1、声明委托

    委托使用关键字 delegate 进行定义。

    例子:

    定义一个返回类型为void参数为一个int的名为IntMethodInvoker的委托

    delegate void IntMethodInvoker(int x);

    因为定义委托基本上就是定义一个新类,所以可以在定义类的任何相同地方定义委托。可以在委托定义上应用常见的访问修饰符:public、private、protected等。

    2、使用委托

     1 delegate int CalculateMethodInvoker(int x, int y);
     2 class Program
     3 {
     4     static void Main(string[] args)
     5     {
     6         CalculateMethodInvoker calculateMethodInvoker = CalculateMethodHelper.Sum;
     7         int x = 100, y = 200;
     8         Console.WriteLine("x,y相加:{0}", Calculate(calculateMethodInvoker, x, y));
     9         calculateMethodInvoker = CalculateMethodHelper.Multiply;
    10         Console.WriteLine("x,y相乘:{0}", Calculate(calculateMethodInvoker, x, y));
    11         Console.ReadKey();
    12     }
    13     public static int Calculate(CalculateMethodInvoker calculateMethodInvoker, int x, int y)
    14     {
    15         return calculateMethodInvoker(x, y);
    16     }
    17 }
    18 public class CalculateMethodHelper
    19 {
    20     public static int Sum(int x, int y)
    21     {
    22         return x + y;
    23     }
    24     public static int Multiply(int x, int y)
    25     {
    26         return x * y;
    27     }
    28 }

    运行以上代码,结果如下:

     

    为了减少输入量,只需要委托实例,就可以只传递地址的名称。这称为委托推断。

    3、Action<T>Func<T>委托

    除了为每个参数和返回类型定义一个新的委托类型外,还可以使用Action<T>Func<T>委托。

    泛型Action<T>委托表示引用一个void返回类型的方法,没有泛型参数的Action类可调用没有参数的方法。

    泛型Func<T>委托表示引用一个有返回值的方法。

    4、多播委托

    委托也可以包含多个方法。这种委托成为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。多播委托识别运算符“-”、“+”、“-=”、“+=”以从委托中增加或删除方法调用。

    例子:

     1 class Program
     2 {
     3     static void Main(string[] args)
     4     {
     5         Action<int, int> calFunc = CalculateMethodHelper.Sum;
     6         calFunc += CalculateMethodHelper.Multiply;
     7         int x = 100, y = 200;
     8         Calculate(calFunc, x, y);
     9         Console.ReadKey();
    10     }
    11     public static void Calculate(Action<int, int> calculateMethodInvoker, int x, int y)
    12     {
    13         Console.WriteLine("运行结果:");
    14         calculateMethodInvoker(x, y);
    15     }
    16 }
    17 public class CalculateMethodHelper
    18 {
    19     public static void Sum(int x, int y)
    20     {
    21         Console.WriteLine("x,y相加:{0}", x + y);
    22     }
    23     public static void Multiply(int x, int y)
    24     {
    25         Console.WriteLine("x,y相乘:{0}", x * y);
    26     }
    27 }

    如果通过委托调用的其中一个方法抛出异常,整个迭代就会停止。解决的方法是,使用Delegate类中定义的GetInvocationList()方法获取Delegate对象数组,再使用循环遍历执行,在过程中捕获异常,来继续下一次迭代。

    5、匿名方法

    匿名方法是用作委托的参数的一段代码。

    例子:

    Action<int, int> calFunc = delegate (int i, int j)
    {
        Console.WriteLine("x,y相加:{0}", i + j);
    };

    在匿名方法中不可使用跳转语句(break、goto或continue),在匿名方法内部不能访问不安全代码,不能访问在匿名方法外部使用的ref和out参数。

    (三)lambda表达式

    C#3.0开始,可以使用新的语法把实现代码赋予委托,只要有委托参数类型的地方,就可以使用lambda表达式。

    例子:

    Action<int, int> calFunc = (i, j) =>
    {
        Console.WriteLine("x,y相加:{0}", i + j);
    };

     

    1、参数

    lambda表达式有几种定义参数的方式。如果只有一个参数,只写出参数名就足够了。如果除一个参数以外,需要圆括号把参数名括起来。

    例子:

    Action<int> one = i =>
    {
        //方法内容
    };
    Action<int, int> two = (i, j) =>
    {
        //方法内容
    };

     

    2、多行代码

    如果lambda表示只有一条语句,在方法块内就不需要花括号和return语句,因为编译器会隐式添加return。

    例子:

    Func<int> lambdaOne = () => 0;

    如果实现代码超过一行,就需要使用return语句显式返回。

    例子:

    Func<int> lambdaOne = () =>
    {
        int i = 0;
        i++;
        ++i;
        return i;
    };

     

    3、闭包

    通过lambda表达式可以访问lambda表达式块外部的变量。这称为闭包。

    例子:

    int param = 10;
    Action<int> lambdaSecond = (i) =>
    {
        Console.WriteLine(i + param);
    };
    lambdaSecond(3);
    Console.ReadKey();

    运行以上代码,结果如下:

     

     

    (四)事件

    事件基于委托,为委托提供了一种发布/订阅机制。

    例子:

     1 class Program
     2 {
     3     static void Main(string[] args)
     4     {
     5         AlarmClock alarmClock = new AlarmClock();
     6         Student zsStudent = new Student("张三");
     7         alarmClock.ItsGetUpClockEvent += zsStudent.ItsGetUpClock;
     8         alarmClock.ItsGetUpClock();
     9         Student lsStudent = new Student("李四");
    10         WeakEventManager<AlarmClock, EventArgs>.AddHandler(alarmClock, "ItsGetUpClockEvent", lsStudent.ItsGetUpClock);//弱事件
    11         alarmClock.ItsGetUpClock();
    12         Console.ReadKey();
    13     }
    14 
    15 }
    16 //事件发布类
    17 public class AlarmClock
    18 {
    19     public event EventHandler<EventArgs> ItsGetUpClockEvent;
    20     public void ItsGetUpClock()
    21     {
    22         Console.WriteLine("时间到,起床了!");
    23         ItsGetUpClockEvent?.Invoke(this, new EventArgs());
    24     }
    25 }
    26 //事件侦听类
    27 public class Student
    28 {
    29     public string Name { get; set; }
    30     public Student(string name)
    31     {
    32         this.Name = name;
    33     }
    34     public void ItsGetUpClock(object sender, EventArgs e)
    35     {
    36         Console.WriteLine("{0}关掉闹钟,起床了。",Name);
    37     }
    38 }
  • 相关阅读:
    Linux安装MySQL5.7.25
    Linux配置jdk
    SpringBoot junit 测试
    SpringBoot jasypt 对配置文件项加密
    关于Hibernate级联操作的总结
    GROUP BY 和 ORDER BY一起使用时,要注意的问题!
    web.xml 中的listener、 filter、servlet 加载顺序及其详解
    Hibernate对象的生命周期(补充)
    hibernate--持久对象的生命周期介绍
    开发属于你自己的标签库!
  • 原文地址:https://www.cnblogs.com/dlxh/p/6643574.html
Copyright © 2020-2023  润新知