C#图解教程(第四版)小笔记——委托与事件

委托 delegate

可以认为委托是一个持有一或多个方法的对象,执行委托,会执行它所“持有”的所有方法。
所有的委托类型都派生于System.MulticastDelegate,而它又派生于System.Delegate。
可以把委托看成一个包含有序方法列表的对象。
在这里插入图片描述

声明委托类型

在这里插入图片描述
不需要在类内部声明,因为它是一种类型声明。
在这里插入图片描述
在创建委托类型变量时,可使用new也可不使用,因为在方法名称和其相应委托类型之间存在隐式转换。

创建委托对象

//声明委托类型的变量
MyDel md;
//两个等价的创建语法
md = new MyDel(Function1);
md = Function1;
//使用匿名方法
md = delegate(int x){ System.Console.WriteLine(x);}

委托的组合——多播

使用“+”、“+=”、“-=”可以组合多个委托或为委托添加(删除)方法。
注:委托是引用类型(不可变),所以实际上上示运算结果是变量指向一个新的委托。
移除方法时,将从列表最后开始搜索,并移除第一个匹配的实例。
删除不存在的方法没有效果。

调用委托

调用空委托会抛出异常。
调用委托时传入的参数会用于调用列表中的每一个方法(除非有输出参数)

委托有返回值的情况

返回调用列表中最后一个方法的返回值。

带引用参数的委托

调用列表中每个方法执行完毕之后,下一个方法的参数会传入上一个方法修改过的新值。

匿名方法和lambda表达式

在这里插入图片描述
若匿名方法不使用任何参数,且委托的参数列表没有输出参数(out),可以使用空圆括号或省略圆括号方式简化匿名方法的参数列表。——调用委托时依然要传入参数。

delegate void MyDel(int x);
MyDel md;
md = delegate /*无参省略圆括号*/ {
	//statement
};
md(i);		//不传参会报错

若委托声明包含数组参数(params),则匿名方法参数列表将忽略params关键字

delegate void ParamsDel(int x, params int[] Y);
ParamsDel pd = delegate (int x, /*省略params*/ int[]Y){……};

捕获外部变量

在匿名方法外部定义的变量,可以在匿名方法中使用,称为捕获(capture)。
在匿名方法内修改变量的值时,外部变量也会被修改。

delegate void OuterDel();
int x = 0;
OuterDel od = delegate {
	x += 2;
	Console.WriteLine("In anonymous function x is: {0}", x);
}
od();		// x = 2
Console.WriteLine("After all statements, x becomes: {0}", x);		// x = 2

只要捕获方法还是委托的一部分,就算变量已经离开了作用域,捕获的外部变量也会一直有效。
在这里插入图片描述

lambda表达式

MyDel del = delegate(int x){return x + 1;};		// 匿名函数
Medel del1 = (int x) => {return x + 1;};	//lambda表达式,省略delegate关键字
Medel del2 = (x) => {return x + 1;};		//lambda表达式,进一步省略类型
Medel del3 = x => {return x + 1;};			//lambda表达式,只有一个隐式参数,省略圆括号
Medel del4 = x => x + 1;			//lambda表达式,进一步省略return

除非有ref或out参数,否则可以省略参数类型。
没有参数必须使用空括号。

事件 event

发布者订阅者模式

在这里插入图片描述
在这里插入图片描述

事件

在这里插入图片描述

声明事件

事件需声明在一个类(发布者)内;
需要委托类型,任何附加到事件(如注册)的处理程序都必须与委托类型的签名和返回类型匹配。
public;
不能使用new来创建对象。
多个事件名使用逗号分隔,可在一条语句内声明多个事件。
在这里插入图片描述
事件是成员,不能在一段可执行代码中声明。事件成员隐式自动初始化为null。

订阅事件

使用+=-=)运算符为事件增加(删除)处理程序。

CLassA.EventA += FuncA;				//为事件注册实例方法
ClassA.EventA += ClassB.FuncB;		//为事件注册静态方法
ClassA.EventA += new EventHandler(cc.FuncC);	//委托形式

ClassA.EventA += () => a++;		//lambda表达式
ClassA.EventA += delegate{a++;};	//匿名函数

触发事件

触发事件的语法和调用方法一样:
在这里插入图片描述

标准事件的用法

事件使用的标准模式的根本是System命名空间声明的EventHandler委托类型。

public delegate void EventHandler(object sender, EventArgs e);

第一个参数(sender)用来保存触发事件的对象的引用;
第二个参数(EventArgs)用来保存状态信息,指明声明类型适用于该程序。EventArgs设计为不能传递热门和数据,若想传递数据,则需要自定义一个派生自EventArgs的类(类名以EventArgs结尾),保存需要的数据。

通过扩展EventArgs来传递数据

可以通过泛型委托声明事件。

//自定义类扩展EventArgs
public class MyEventArgs : EventArgs{
	public int MyData{ get; set; };		//存储需要的数据
}

//通过泛型委托获取事件
public event EventHandler<MyEventArgs> MyEvent;

事件访问器

add和remove访问器,声明类似类的属性。
声明了事件访问器之后,事件不包含任何内嵌委托对象,必须实现自己的机制来存储和移除事件注册的方法。
访问器内不能包含return语句。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值