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. fw:理解RESTful架构

    理解RESTful架构   作者: 阮一峰 日期: 2011年9月12日 越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软件"采用客户端/服务器模式,建立 ...

  2. BZOJ1407_NOI2002_荒岛野人_Savage_C++

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1407 题解:http://www.cnblogs.com/hadilo/p/5951091.h ...

  3. Java后台工程师面试杂记——不跳不涨工资星人跳槽经历

    经过接近一个月的时间,完成换工作这件“小事”,前后总计面试了多家公司,最后也没接到几个offer,不过最终总算尘埃落定,就对这个过程进行一个总结吧. 在某互联网公司工作了近一年的时间,但是频繁的业务需 ...

  4. js 数组对象,数组的使用

    var a =new Array(1,2,3,4,'a','b','c',{x:1,y:2}); alert(a[7].x); //数组之中可以定义数组. var b=['a','b','c']; c ...

  5. HTML DOM(学习笔记一)

    嗯,工作也有一段时间了,对编程的认识也深入了一些,以前认为HTML/CSS/JAVASCRIPT是比较简单的,看网上的教程就可以了,W3C是我学习这些知识常去的一个网站,非常感谢她让我学习到了更多的一 ...

  6. Android入门之GridView(表格控件)

    GridView是一个表格控件,可以在每个单元格中显示自定义的View或者字符串.在这里我们要实现一个图标下方有文字的效果. 1.首先我们应自定义布局文件image_text.xml.代码如下: &l ...

  7. 网络设备模拟器 GNS3

    https://www.gns3.com/support/docs/linux-installation sudo dpkg --add-architecture i386 sudo add-apt- ...

  8. python3的文件操作

    open的原型定义在bultin.py中,是一种内建函数,用于处理文件 open(file, mode='r', buffering=None, encoding=None, errors=None, ...

  9. verilog实现奇数倍分频

    在学习FPGA的过程中,最简单最基本的实验应该就是分频器了, 同时分频器也是FPGA设计中使用频率非常高的基本设计之一, 尽管在芯片厂家提供的IDE中集成了锁相环IP, 如altera 的PLL,Xi ...

  10. linux进程状态

    系统维护的时候难免会遇到进程的状态的查询和管理,到底什么是R,有的是S,有的还是S+呢?一直有些混沌的问题,今天细细的来总结一下: ps是用来报告系统中程序执行状况的命令这个是无可厚非的,linux进 ...