编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]
前言
本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:
建议38、小心闭包中的陷阱
建议39、了解委托的实质
建议40、使用event关键字对委托施加保护
建议41、实现标准的事件模型
建议38、小心闭包中的陷阱
首先我们先来看一段代码:
class Program
{
static void Main(string[] args)
{
List<Action> list = new List<Action>();
for (int i = ; i < ; i++)
{
Action t = () =>Console.WriteLine(i.ToString());
list.Add(t);
}
foreach (Action t in list)
{
t();
}
Console.ReadLine();
}
}
你设想的结果或许是0,1,2,3,4
但没想到执行后结果如下

通过IL可以查看代码,组合后大致代码如下:
public class TempClass
{
public int i;
public void TempFunc()
{
Console.WriteLine(i.ToString());
} }
class Program
{
static void Main(string[] args)
{
List<Action> list = new List<Action>();
TempClass tempClass = new TempClass();
for (tempClass.i = ; tempClass.i < ; tempClass.i++)
{
Action t = tempClass.TempFunc;
list.Add(t);
}
foreach (Action t in list)
{
t();
}
Console.ReadLine();
}
}
当然运行后结果还是5,5,5,5,5
其实这段代码所演示的就是一个闭包对象。所谓的闭包对象,指的是上面这种情形中的TempClass对象,如果匿名方法(Lambda表达式)引用了某个局部变量,编译器就会自动将该引用提升到该闭包对象中,即将for循环中的变量i修改成了引用闭包对象的公共变量i。这样一来,即使代码执行后离开了原局部变量i的作用域(如for循环),包含该闭包对象的作用域也还存在。
下面简单修改一下之前的代码
class Program
{ static void Main(string[] args)
{
List<Action> list = new List<Action>();
for (int i = ; i < ; i++)
{
int temp = i;
Action t = () => Console.WriteLine(temp.ToString());
list.Add(t);
}
foreach (Action t in list)
{
t();
}
Console.ReadLine();
}
}
执行结果如下:

建议39、了解委托的实质
http://www.cnblogs.com/aehyok/archive/2013/03/22/2976356.html这里有我之前对委托的简单的学习过程,虽然在工作中很少用,几乎就没用。不过还是拿来学习学习。
理解委托需要把握两个点:
1、委托是方法指针。
2、委托就是一个类。当对其进行实例化的时候,要将引用方法作为它构造函数的参数。
建议40、使用event关键字对委托施加保护
http://www.cnblogs.com/aehyok/archive/2013/02/22/2922586.html 这也是对于事件的简单理解学习。
建议41、实现标准的事件模型
我们应该知道微软为事件模型设定的几个规范:
1、委托类型的名称以EventHandler结束。
2、委托原型返回值为void。
3、委托原型具有两个参数:sender表示事件触发者,e表示事件参数。
4、事件参数的名称以EventArgs结束。
public class FileUploadedEventArgs : EventArgs
{
public int FileProgress { get; set; }
} public class FileUploader
{
public event EventHandler<FileUploadedEventArgs> FileUploaded; public void Upload()
{
FileUploadedEventArgs e = new FileUploadedEventArgs() { FileProgress= };
while (e.FileProgress > )
{
///传输代码,省略
e.FileProgress--;
if (FileUploaded != null)
{
FileUploaded(this, e);
}
}
}
}
最终进行调用的代码如下:
class Program
{
static void Main(string[] args)
{
FileUploader fileUploader = new FileUploader();
fileUploader.FileUploaded += Progress;
fileUploader.Upload();
Console.ReadLine();
} static void Progress(object sender,FileUploadedEventArgs e)
{
Console.WriteLine(e.FileProgress);
}
}
英语小贴士
1、Hello. This is United Airlines.——联合航空,您好。 I'd like to reconfirm my flight.——我想要再确认班机。
2、What's your name and flight number?——请说您的大名与班机号码?
3、My name is Jerry Cheng, and the flight number is UA 003 for Los Angeles.——我的名字是杰瑞‧陈,班机号码是飞往洛杉机的联合航空003班机。
4、When is it?June 10th.——行程是那一天?6月10日。
5、I'd like to make sure of the time it leaves.——我想要确认班机时间没有改变。
6、I can't find your name. Really?——我找不到您的大名。真的? May I have your name again?——请再告诉我一次您的大名?
7、I still can't find your name on the reservation list.——我仍然无法在订位名单中找到您的名字。
8、Anyway, we have seats for new bookings on this flight. No problem.——别担心,这班班机仍有空位提供新的订位者。
9、One economy class seat, is that right?——一个经济舱座位,对吗? Now you have been booked.——没问题,您已完成订位。
10、Thanks a lot. What time do you start check-in?——谢谢。你们何时开始办理登机?
11、Two hours before departure time.——起飞前2小时。 You must check-in at least one hour before.——你必须在至少1小时前办理登机。
作者:aehyok
出处:http://www.cnblogs.com/aehyok/
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,那不妨点个推荐吧,谢谢支持:-O。
编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]的更多相关文章
- 编写高质量代码改善C#程序的157个建议[1-3]
原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...
- 读书--编写高质量代码 改善C#程序的157个建议
最近读了陆敏技写的一本书<<编写高质量代码 改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...
- 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试
建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...
- 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本
建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...
- 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码
建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...
- 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣
建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...
- 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释
建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...
- 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释
建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...
- 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量
建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...
随机推荐
- css常见问题
CSS: 1.垂直居中布局 (1)已知宽高 (2)未知宽高 https://segmentfault.com/q/1010000004073623 2.文字退格 text-indent: 4em; 3 ...
- Linux NFS 介绍
由SUN开发,用于在不同的系统之间使用,所以其设计与主机系统无关,用户想使用远程文件时,只需要mount –t nfs就可以把远程的文件拿到本地,像使用本地文件一样使用,非常方便. 它采用C/S架构, ...
- Python HeapSort
__author__ = 'student' print 'hello world hello python' ''' heap sort root leftchild 2n+1 rightchild ...
- WordCount Analysis
1.Create a new java project, then copy examples folder from /home/hadoop/hadoop-1.0.4/src; Create a ...
- tika提取pdf信息异常
org.apache.tika.sax.WriteOutContentHandler$WriteLimitReachedException: Your document contained more ...
- c++获取sqlite3数据库表中所有字段的方法
常用方法: 1.使用sqlite3_get_table函数 2.获取sqlite创建表的sql语句字符串,然后进行解析获取到相应的字段 3.采用配置文件的方式,将所有字段名写入配置文件 方法1:使用s ...
- PAC学习框架
PAC学习框架是机器学习的基础.它主要用来回答以下几个问题: 什么问题是可以高效学习的? 什么问题本质上就难以学习? 需要多少实例才能完成学习? 是否存在一个通用的学习模型? PAC=probably ...
- Linux 系统常用命令汇总(六) 文件打包与压缩
文件打包与压缩 命令 选项 注解 示例 compress 文件名 压缩指定的文件,压缩后的格式为*.z compress install.log -d 解压被压缩的文件 .z为后缀的文件:compr ...
- codeforces 711D D. Directed Roads(dfs)
题目链接: D. Directed Roads time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- 在3D Max中查看模型引用的贴图
需求 假如在Max中有一个模型,想查看贴图 操作步骤 1.右上角点击 2.在弹出材质编辑器中 点击吸管 3.把吸管点击在角色模型上,然后点击M 4.点击查看图像 5.就能查看到模型使用的贴图