1. 概述

  本章讲解如何使用 委托、lambda表达式 和 匿名方法 来创建和使用事件。

2. 主要内容

  2.1 理解委托

    委托是一种用方法签名形式定义的类型。可以让它指向其他方法,可以通过它调用其他方法。

    ① 委托支持多播(multicasting),可以用 + 和 += 操作符绑定多个方法到委托中(用 - 和 -= 取消绑定)。

public void Method1() {}
public void Method2() {} public delegate void Del(); public void Multicast()
{
Del d = Method1;
d += Method2; d();
}

    ② 需要绑定到委托的方法,签名不一定非得和委托完全一致。有两种特殊情况:

      Covariance:如果方法的返回值类型派生自委托的返回值类型,则该方法可以绑定到该委托。

public delegate TextWriter CovarianceDel();

public StreamWriter MethodStream() { return null; }
public StringWriter MethodString() { return null; } CovarianceDel del = MethodStream;
del = MethodSting;

      Contravariance:如果委托的参数类型派生自方法的参数类型,则该方法可以绑定到该委托。

void DoSomething(TextWriter tw) { }
public Delegate void Contravariance(StreamWriter sw); Contravariance = DoSomething;

  2.2 使用 Lambda 表达式

    Lambda表达式是匿名方法的升级版。

Calculate calc = (x, y) => x + y;
Console.WriteLine(calc(, )); //Displays 7

    有时候为某些事件声明专用的委托类型会感觉比较笨拙,鉴于此,系统内建了两个委托类型来简化开发    

    Func<...> : 支持0-16个参数,一个返回值。

    Action<...>: 支持0-16个参数,无返回值。

Action<int, int> calc = (x, y) =>
{
Console.WriteLine(x + y);
}; calc(, ); // displays 7

    *闭包(closure):如果一个委托引用了一个本地变量,并且被返回给了调用方。这时委托就具备了比该变量更长的作用域。

      为了避免这种情况,编译器会生成相应的代码去保证该变量具有和委托一样长的声明周期。(纯翻译,不知道理解的对不对。。)

  2.3 使用事件

    订阅和发布 是 一种流行的设计模式,用于实现同类问题的重用方案。

public class Pub
{
public Action OnChange { get; set; } public void Raise()
{
if (OnChange != null)
OnChange();
}
} public void CreateAndRaise()
{
Pub p = new Pub();
p.OnChange += () => Console.WriteLine("Raise method1");
p.OnChange += () => Console.WriteLine("Raise method2");
p.Raise();
}

    上述代码使用委托实现的订阅机制,有以下问题:

    ① 如果把method2订阅时的 += 换成 =,就会覆盖掉前面method1的订阅。

    ② OnChange是公共属性,外部用户可以随意调用。

    为了避免上述问题,C#推出了 event 关键字。

public class Pub
{
public event Action OnChange = delegate { }; public void Raise()
OnChange();
}

    上述代码中的Action可以换成EventHandler<T>委托,可以用于传递数据。

    下面是包含异常处理的代码

public class Pub
{
public event EventHandler OnChange = delegate {};
public void Raise()
{
var exceptions = new List<Exception>(); foreach(Delegate handler in OnChange.GetInvocationList())
{
try
{
handler.DynamicInvoke(this, EventArgs.Empty);
}
catch(Exception ex)
{
exceptions.Add(ex);
}
} if (exceptions.Any())
throw new AggregatedException(exceptions);
}
} public void CreateAndRaise()
{
Pub p = new Pub(); p.OnChange += (sender, e) =>Console.WriteLine("1 called");
p.OnChange += (sender, e) =>{ throw new Exception();};
p.OnChange += (sender, e) =>Console.WriteLine("3 called"); try
{
p.Raise();
}
catch(AggregatedException ex)
{
Console.WriteLine(ex.InnerExceptions.Count);
}
}

3. 总结

  ① 委托是一个具有方法签名方式的类型,可以包含一个指向方法的引用。

  ② 委托可以被实例化,传递 和 触发。

  ③ Lambda表达式使用 => 操作符来创建匿名方法。

  ④ event是基于委托机制,高于委托机制的语法糖,可以方便的实现发布-订阅机制。

  ⑤ event只能在声明他的类内被触发。event使用者只能删除和添加invocation列表的方法。

  ⑥ 可以自定义事件访问器或者直接使用内建的委托类型。

第四章 管理程序流(In .net4.5) 之 事件和回调的更多相关文章

  1. 第三章 管理程序流(In .net4.5) 之 实现程序流

    1. 概述 本章内容包括 布尔表达式.流控制方式.集合遍历 以及 流跳转. 2. 主要内容 *由于该章内容比较基础,日常用的也很多,故对一些常用的基础内容不再赘述. 2.1 使用布尔表达式 熟悉下列比 ...

  2. 第五章 管理程序流(In .net4.5) 之 异常处理

    1. 概述 本章包括.net4.5中异常处理相关的部分. 2. 主要内容 2.1 处理异常 ① try.cahtch.finally 机制,无需多言. ② 使用 Environment.FailFas ...

  3. 第一章 管理程序流(In .net4.5) 之 实现多线程和异步处理

    1. 概述 本章主要讲解.net4.5如何实现多线程和异步处理的相关内容. 2. 主要内容 2.1 理解线程 ① 使用Thread类   public static class Program   { ...

  4. 第二章 管理程序流(In .net4.5) 之 管理多线程

    1. 概述 本章包括同步资源以及取消长时间任务相关的内容. 2. 主要内容 2.1 同步资源 ① lock关键字实现.会阻塞程序,有可能会导致死锁. ② volatile关键字可以禁用编译优化,用于避 ...

  5. Netty源码分析第4章(pipeline)---->第6节: 传播异常事件

    Netty源码分析第四章: pipeline 第6节: 传播异常事件 讲完了inbound事件和outbound事件的传输流程, 这一小节剖析异常事件的传输流程 首先我们看一个最最简单的异常处理的场景 ...

  6. 精通Web Analytics 2.0 (6) 第四章:点击流分析的奇妙世界:实际的解决方案

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第四章:点击流分析的奇妙世界:实际的解决方案 到开始实际工作的时候了.哦耶! 在本章中,您将了解到一些最重要的网络分析报告,我将 ...

  7. 读书笔记,《Java 8实战》,第四章,引入流

       集合是Java中使用最多的API,但集合操作却远远算不上完美.主要表现在两点,    第一,集合不能让我们像数据库的SQL语言一样用申明式的语言指定操作:    第二,现在的集合API无法让我们 ...

  8. 20190827 On Java8 第十四章 流式编程

    第十四章 流式编程 流的一个核心好处是,它使得程序更加短小并且更易理解.当 Lambda 表达式和方法引用(method references)和流一起使用的时候会让人感觉自成一体.流使得 Java ...

  9. 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...

随机推荐

  1. Android——主流分辨率

    VGA:480*640 QVGA:240*320 HVGA:320*480 WVGA:480*800 FWVGA:480*854 IntelHaxm.exe  模拟器加速器

  2. linux多线程

    #include <pthread.h> pthread_t pid; pthread_create(&pid, 0, pFunc, pArgs); //创建线程(linux下线程 ...

  3. 如何实现从Android第三方平台推送微信公众号

    最近心血来潮,想要尝试写写有关实现Android平台第三方应用软件去跳转到微信平台的代码.我只是先暂时写写我的思路,如后期实现,便将主要代码附上. 微信公众平台官方宣布微信沟通接口正式上线,用户可以在 ...

  4. SDUT 3311 数据结构实验之串三:KMP应用

    数据结构实验之串三:KMP应用 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 有n个小朋友 ...

  5. NAT学习笔记

    NAT介绍 NAT, 全称网络地址转换(Network Address Translation),是一种在IP封包通过路由器或防火墙时重写来源IP地址或目的IP地址的技术. NAT的分类及介绍 NAT ...

  6. Robotlegs2 学习笔记 -- SwiftSuspenders 2.x (2)

    Swiftsuspenders2简介 Swiftsuspenders2是一个基于元数据(metadata)的IOC(控制反转,inversion of control)的AS3的解决方案.(对于元数据 ...

  7. 免费的API接口

    有如下三个Json格式的查询天气预报接口: http://www.weather.com.cn/data/sk/101010100.html http://www.weather.com.cn/dat ...

  8. MSP430F149学习之路——按键与LED

    代码 /*********************************** 程序功能:用按键控制LED状态 缺点:按键按下后无法改变LED灯的状态,可以利用板上的复位键^~^ ********** ...

  9. yii中的若干问题

    一直觉得”程序猿“是个很细致的工作,就像绣花一样,一不小心缝错一针,就可能是个很大的bug,但是为什么平时看起来大而化之的男同胞们确能在这方面如此care呢?? 以下进入正文,省去华丽丽的词语,这里仅 ...

  10. 学习总结 java 异常

    package com.hanqi.ec; public class Test1 { public static void main(String[] args) { int a = 10 , b = ...