(一)引用方法

委托是寻址方法的.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 }

【读书笔记】C#高级编程 第八章 委托、lambda表达式和事件的更多相关文章

  1. C#编程 委托 Lambda表达式和事件

    委托 如果我们要把方法当做参数来传递的话,就要用到委托.简单来说委托是一个类型,这个类型可以赋值一个方法的引用. 声明委托 在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字段和方 ...

  2. 读书笔记 - js高级程序设计 - 第八章 BOM

      BOM的核心对象是window 它表示浏览器的一个实例,在浏览器中,window对象有双重角色,它既是通过js访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象,这意味着在网 ...

  3. 读书笔记 - js高级程序设计 - 第七章 函数表达式

      闭包 有权访问另一个函数作用域中的变量的函数 匿名函数 函数没有名字 少用闭包 由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存.过度使用闭包可能会导致内存占用过多,我们建议读者 ...

  4. C#学习笔记三(委托·lambda表达式和事件,字符串和正则表达式,集合,特殊的集合)

    委托和事件的区别 序号 区别 委托 事件 1 是否可以使用=来赋值 是 否 2 是否可以在类外部进行调用 是 否 3 是否是一个类型 是 否,事件修饰的是一个对象 public delegate vo ...

  5. C#高级编程(第9版) 第08章 委托、lambda表达式和事件 笔记

          本章代码分为以下几个主要的示例文件: 1. 简单委托 2. 冒泡排序 3. lambda表达式 4. 事件示例 5. 弱事件     引用方法 委托是寻址方法的.NET版本.在C++中函数 ...

  6. Hadoop学习笔记(7) ——高级编程

    Hadoop学习笔记(7) ——高级编程 从前面的学习中,我们了解到了MapReduce整个过程需要经过以下几个步骤: 1.输入(input):将输入数据分成一个个split,并将split进一步拆成 ...

  7. Java并发编程的艺术读书笔记(2)-并发编程模型

    title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...

  8. Java并发编程的艺术读书笔记(1)-并发编程的挑战

    title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...

  9. 《Essential C++》读书笔记 之 C++编程基础

    <Essential C++>读书笔记 之 C++编程基础 2014-07-03 1.1 如何撰写C++程序 头文件 命名空间 1.2 对象的定义与初始化 1.3 撰写表达式 运算符的优先 ...

随机推荐

  1. 程序员必备,一款让你提高工作效率N倍的神器uTools

    下载地址:https://www.aliyundrive.com/s/f7PU7QxdxEz uTools 是什么? uTools = your tools(你的工具集) uTools 是一个极简.插 ...

  2. Python爬取某短视频热点

    写在前面的一些话: 随着短视频的大火,不仅可以给人们带来娱乐,还有热点新闻时事以及各种知识,刷短视频也逐渐成为了日常生活的一部分.本文以一个简单的小例子,简述如何通过Pyhton依托Selenium来 ...

  3. nextInt和nextLine以及next方法的区别

    1.nextInt() 只读取整型的数据,输入读取完之后,光标仍在当前行. 2.nextLine() 扫描到一行内容,当遇见换行符时,结束扫描.一旦输入读取完毕,该方法会将光标移到下一行开始的位置. ...

  4. Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

    上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor).本文在此基 ...

  5. vue在Docker上运行

    Dockerfile # 设置基础镜像 FROM nginx:latest # 定义作者 MAINTAINER test # 将dist文件中的内容复制到 /etc/nginx/html/ 这个目录下 ...

  6. 攻防世界pwn题:Recho

    0x00:查看文件信息 一个64位二进制文件,canary和PIE保护机制没开. 0x01:用IDA进行静态分析 分析:主程序部分是一个while循环,判断条件是read返回值大于0则循环.函数ato ...

  7. 集合容器和Hash表

    集合容器 集合相当于一个容器,在我们使用Arraylist的时候添加参数相当与放了一个容器中.这里面的元素是可以重复的 在HashSet中添加元素是没有重复的,我们来写一个测试看一下 public s ...

  8. 09 MySQL_SQL日期函数和聚合函数

    日期相关的函数 seclect 'helloworld'; 1. 获取当前时间 now(); select now(); 2.获取当前的日期 curdate(); select curdate(); ...

  9. 啥也不是 -「OI 易犯错误整理」

    原帖出自 Nefelibata,不过他不想维护,所以就交给 STrAduts 了 awa.因为一些不可抗力,帖主转移至 XSC062.申请置顶! 前言 Nefelibata:因为笔者弱到无法形容,因此 ...

  10. python 装饰器理解

    简介 装饰器可以在不修改原有代码的基础上添加新的功能,可以将重复重用的代码抽取出来,进一步解耦,方便维护,一般适用于插入日志.性能测试.事务处理.缓存等 装饰器的前提 闭包 一般来说,当一个函数嵌套另 ...