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. JAVA Socket:文件传输

    客户端:读取文件(FileInputStream),发送文件(OutputStream) 服务器端:接收文件(InputStream),写文件(FileOutputStream) 客户端代码: pac ...

  2. Android popupwindow 弹出的位置问题

    在Android开发中,需要用到PopupWindow这个类.在初始化完成,显示之前,都需要获得这个对象的width,height去计算popupWindow弹出的位置. 这个时候会发现取得的widt ...

  3. Cv运动分析与对象跟踪(转)

    Cv运动分析与对象跟踪   目录 [隐藏] 1 背景统计量的累积 1.1 Acc 1.2 SquareAcc 1.3 MultiplyAcc 1.4 RunningAvg 2 运动模板 2.1 Upd ...

  4. 利用canvas实现的中点Bresenham算法

    Bresenham提出的直线生成算法的基本原理是,每次在最大位移方向上走一步,而另一个方向是走步还是不走步取决于误差项的判别,具体的实现过程大家可以去问度娘.我主要是利用canvas画布技术实现了这个 ...

  5. 利用DataTable快速批量导数据

    DataSet ds = new DataSet();            using (SqlConnection conn = new SqlConnection(@"data sou ...

  6. VS/Visual studio 源代码编辑器里的空处出现点号解决办法

    此原因是不小心按错了键盘上的组合键Ctr+E+S, 再次按Ctr+E+S可消除.

  7. angular factory Services provider 自定义服务 工厂

    转载于 作者:海底苍鹰地址:http://blog.51yip.com/jsjquery/1602.html 1.在app.js 中声明了模块的依赖 var phonecatApp = angular ...

  8. 代码轮子之很简单但是挺管用的基于C# Task的模拟并发的代码

    代码轮子之很简单但是挺管用的基于C# Task的模拟并发的代码

  9. servlet 启动加载配置文件及初始化

    在servlet开发中,会涉及到一些xml数据的读取和一些初始化方法的调用.可以在tomcat启动的时候,加载一个servlet去初始化一些数据. 摘自 http://stone02111.iteye ...

  10. 一个Brushes笔画应用ios源码完整版

    效果很不错的画笔App,提供几十种不同的画笔,包括毛笔画笔.拥有绘画App的一些基本功能,包括颜色选择.绘画保存,支持撤销(undo).重做(redo)以及橡皮擦功能等等,甚至还支持类似PhotoSh ...