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. H264的句法和语法总结(一)分层结构

    在H.264 中,句法元素共被组织成  序列.图像.片.宏块.子宏块五个层次.在这样的结构中,每一层的头部和它的数据部分形成管理与被管理的强依赖关系,头部的句法元素是该层数据的核心,而一旦头部丢失,数 ...

  2. Hive基础之COALESCE用法

    语法: COALESCE(T v1, T v2, …) 返回参数中的第一个非空值:如果所有值都为NULL,那么返回NULL 以emp表为例: desc emp; empno int None enam ...

  3. CString.Format的详细用法(转)

    CString.Format的详细用法(转) 在MFC程序中,使用CString来处理字符串是一个很不错的选择.CString既可以处理Unicode标准的字符串,也可以处理ANSI标准的字符串.CS ...

  4. Android开发-API指南-设备兼容性

    Device Compatibility 英文原文:http://developer.android.com/guide/practices/compatibility.html 采集日期:2014- ...

  5. 关于ORA-04021解决办法(timeout occurred while waiting to lock object)

    某个应用正在锁定该表或者包 表为 select b.SID,b.SERIAL#,c.SQL_TEXT from v$locked_object a, v$session b, v$sqlarea c ...

  6. EXT学习之——Extjs 文本框 TextField 添加点击(onclick)事件方法

    { xtype:'textfield', listeners: { render: function(p) { // Append the Panel to the click handler's a ...

  7. 学习总结 for循环--冒泡排序

    //输入N个人的分数,按从高到低进行排序 Console.Write("请输入人数"); int n = int.Parse(Console.ReadLine()); int[] ...

  8. WF4 持久化 <第四篇>

    一.基础示例 WF4 默认支持SQLServer的持续化,首先要执行目录C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en下的脚本: SqlPer ...

  9. javascript之toString()和valueOf()函数

    1.我们为什么要了解这两种方法 众所周知,toString()函数和valueOf函数,这两个函数是Object类的对象生来就拥有的,而且他们还可以允许我们重写,那么,这两个函数到底有什么用呢? 从名 ...

  10. grep,awk和sed的常用命令和语法

    Grep的常用命令语法 1. 双引号引用和单引号引用在g r e p命令中输入字符串参数时,最好将其用双引号括起来.例如:“m y s t r i n g”.这样做有两个原因,一是以防被误解为 s h ...