C#委托事件Lambda

测试代码链接

什么是委托:
委托是寻址方法的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。我们无法判断这个指针实际指向什么,像参数和返回类型等项就更无从知晓了。
而NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对方法的引用,也可以包含多个方法的引用。
lambda表达式与委托直接相关,当参数是委托类型时,就可以使用lambda表达式实现委托引用的方法。

定义委托:
private delegate string GetAString();他给方法的签名和返回类型指定名称
实际上,定义一个委托是指定义一个新类。委托实现为派生自基类System.MulticastDelegate类,System.MulticastDelegate又派生自基类System.Delegate。

使用委托:
GetAString firstStringMethod = x.ToString;
给定委托的实例可以引用任何类型的任何对象上的实例方法或静态方法,只要方法的签名匹配于委托的签名即可。

调用委托:
firstStringMethod() 或firstStringMethod.Invoke();

除了为每个参数和返回类型定义一个新委托类型之外,还可以使用Action和Func委托。
泛型Action委托表示引用一个void返回类型的方法。这个委托类存在不同的变体,可以传递至多16种不同的参数类型。没有泛型参数的Action类可调用没有参数的方法。Action调用带一个参数的方法, Action<inTI, in T2>调用带两个参数的方法, Action<in Tl, in T2, in T3, in T4, in T5, in T6, in T7, in T8>调用带8个参数的方法。
泛型Func委托可以以类似的方式使用。Func允许调用带返回类型的方法。与Action<T类似,Func也定义了不同的变体,至多也可以传递16个参数类型和一个返回类型。Func委托类型可以调用带返回类型且无参数的方法, Func<in T, out TResult>调用带一个参数的方法,Func<in TI, in T2, in T3, in T4, out TResult>调用带4个参数的方法。

多播委托:
前面使用的每个委托都只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显式调用这个委托。但是,委托也可以包含多个方法。这种委托称为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。
通过一个委托调用多个方法还可能导致一个大问题。多播委托包含一个逐个调用的委托集合。如果通过委托调用的其中一个方法抛出一个异常,整个迭代就会停止。
为了避免这个问题,应自己迭代方法列表。Delegate类定义GetInvocationList)方法,它返回一个Delegate对象数组。现在可以使用这个委托调用与委托直接相关的方法,捕获异常,并继续下一次迭代。

匿名方法:
Func<string, string> anonDel = delegate(string param){…}
要想使委托工作,方法必须已经存在(即委托是用它将调用的方法的相同签名定义的)。但还有另外一种使用委托的方式:即通过匿名方法。匿名方法是用作委托的参数的一段代码。

lambda表达式:
自C#3.0开始,就可以使用一种新语法把实现代码赋予委托: lambda表达式。只要有委托参数类型的地方,就可以使用lambda表达式。
Func<string, string> oneParam = s => String.Format(“change uppercase {0}”, s.ToUpper());
Console.WriteLine(oneParam(“test”));

Func<double, double, double> twoParams = (x, y) => x * y;
Console.WriteLine(twoParams(3, 2));

Func<double, double, double> twoParamsWithTypes = (double x, double y) => x * y;
Console.WriteLine(twoParamsWithTypes(4, 2));

Func<double, double> operations = x => x * 2;
operations += x => x * x;//lambda不能用+=实现多播,会直接覆盖。

闭包:
通过lambda表达式可以访问lambda表达式块外部的变量。这称为闭包。闭包是一个非常好的功能,但如果使用不当,也会非常危险。
1.可能会在其他地方对lambda表达式访问访问的外部的变量进行了修改,导致lambda表达式中的外部的变量变得不确定
2.使用C# 4或更早版本的编译器时,在foreach中使用lambda表达式时所有的遍历值都等于遍历最后一项的结果,解决办法:可以在foreach中使用中间变量转接;在C#5.0中不再出现这种问题。

事件:
事件基于委托,为委托提供了一种发布/订阅的机制;委托是类,事件是委托的实例。
事件声明,触发,发布,订阅,看代码

弱事件:
动态创建订阅器时,为了避免出现资源泄露,必须特别留意事件。也就是说,需要在订阅器离开作用域(不再需要它)之前,确保取消对事件的订阅。另一种方法就是使用弱事件。
通过事件,直接连接到发布程序和侦听器。但垃圾回收有一个问题。例如,如果侦听器不再直接引用,发布程序就仍有一个引用。垃圾回收器不能清空侦听器占用的内存,因为发布程序仍保有一个引用,会针对侦听器触发事件。
这种强连接可以通过弱事件模式来解决,即使用WeakEventManager作为发布程序和侦听器之间的中介。

使用委托和事件可以减少依赖性和层的耦合,并能开发出具有更高重用性的组件。lambda表达式是委托的C#语言特性。通过它们可以减少需要编写的代码量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值