原文:编写高质量代码改善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 = 0; i < 5; 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 = 0; tempClass.i < 5; 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 = 0; i < 5; 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=100 }; while (e.FileProgress > 0) { ///传输代码,省略 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。