首页 > 代码库 > 编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]
编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]
前言
泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能。基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用。同时,它减少了泛型类及泛型方法中的转型,确保了类型安全。委托本身是一种引用类型,它保存的也是托管堆中对象的引用,只不过这个引用比较特殊,它是对方法的引用。事件本身也是委托,它是委托组,C#中提供了关键字event来对事件进行特别区分。一旦我们开始编写稍微复杂的C#代码,就肯定离不开泛型、委托和事件。本章将针对这三个方面进行说明。
本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:
建议35、使用default为泛型类型指定初始值
建议36、使用FCL中的委托声明
建议37、使用lambda表达式代替方法和匿名方法
建议35、使用default为泛型类型指定初始值
有些算法,比如泛型集合List<T>的Find算法,所查找的对象有可能会是值类型,也有可能是引用类型。在这种算法内部,我们常常会为这些值类型变量或引用类型变量指定默认值。于是,问题来了:值类型变来那个的默认初始值是0值,而引用类型变量的默认初始值是null值,显然,这会导致下面编译出错:
C#编译器会阻止这样的代码通过编译。要让编译器接收为一个泛型类型参数指定一个初始值,最妥当的办法就是使用default关键字。所以,在上面的代码应该改为:
public T Func<T>() { T t = default(T); return t; }
这样如果它在运行时碰到的T是一个整型,那么运行时会为其赋值0;如果T在运行时是一个Person这样的引用类型,则会为其赋null值。
建议36、使用FCL中的委托声明
要注意FCL中存在三类这样的委托声明,他们分别是:Action、Func、Predicate。尤其是在他们的泛型版本出来以后,已经能够满足我们在实际编码过程中的大部分需要。
这里是之前一篇关于Action、Func、Predicate的有关介绍http://www.cnblogs.com/aehyok/p/3382291.html
除了Action、Func、Predicate外,FCL中还有用于标识特殊含义的委托声明。如用于表示注册事件方法的委托声明:
public delegate void EventHandler(object sender,EventArgs e); public delegate void EnentHandler<TEventArgs>(object sender,TEventArgs e);
表示线程的委托声明:
public delegate void ThreadStart(); public delegate void ParameterizedThreadStart(object obj);
表示异步回调的委托声明:
public delegate void AsyncCallback(IAsyncResult ar);
在FCL中没一类委托声明都代表一类特殊的用途,虽然可以使用自己的委托声明来代替,但是这样做不仅没有必要,而且会让代码失去简洁性和标准型。在我们实现自己的委托声明前,应该首先查看MSDN,确信有必要之后才这样做。
建议37、使用lambda表达式代替方法和匿名方法
首先我们使用Action和Func来做一个简单的小例子,控制台应用程序代码如下所示:
第一个版本
class Program { static int Add(int i, int j) { return i + j; } static void Print(string message) { Console.WriteLine(message); } static void Main(string[] args) { Func<int, int, int> add = Add; Action<string> print = Print; print(add(4, 5).ToString()); Console.ReadLine(); } }
实际上要完成上面的功能,还有多种编码方式,先来看一种最中规中矩的方式,同时也是最繁琐的写法:
第二个版本
class Program { static int Add(int i, int j) { return i + j; } static void Print(string message) { Console.WriteLine(message); } static void Main(string[] args) { Func<int, int, int> add = new Func<int,int,int>(Add); Action<string> print =new Action<string>(Print); print(add(4, 5).ToString()); Console.ReadLine(); } }
其实也就是将第一个版本稍作调整。从上面的写法中也可以看出:Add方法和Print方法实际上都只有一条语句,因此,使用匿名方法也许是一种更好的选择:
第三个版本
static void Main(string[] args) { Func<int, int, int> add = new Func<int,int,int>(delegate(int i,int j) { return i+j; }); Action<string> print =new Action<string>(delegate(string message) { Console.WriteLine(message); }); print(add(4, 5).ToString()); Console.ReadLine(); }
使用匿名方法以后,我们不需要在Main方法外部声明两个方法了,可以直接在Main这个工作方法中完成所有的代码编写,而且不会影响代码清晰性。实际上,所有代码行数不超过3行的方法(条件是它不倍重用),我们都建议采用这种方式来编写。上面的版本继续改进:
第四个版本
static void Main(string[] args) { Func<int, int, int> add = delegate(int i,int j) { return i+j; }; Action<string> print =delegate(string message) { Console.WriteLine(message); }; print(add(4, 5).ToString()); Console.ReadLine(); }
以上代码看上去更简化了,不过,最终极的改进是使用lambda表达式:
第五个版本
static void Main(string[] args) { Func<int, int, int> add = (x, y) => x + y; Action<string> print = (message) => Console.WriteLine(message); print(add(4, 5).ToString()); Console.ReadLine(); }
Lambda表达式操作符”=>“的左侧是方法的参数,右侧是方法体,其本质是匿名方法。实际上,经过编译后Lambda表达式就是一个匿名方法。我们应该在实际的编码工作中熟练运用它,避免写出繁琐且不美观的代码。
英语小贴士
1、Your passport and declaration card, please.——请出示护照和申报单。
2、This is a souvenir that I‘m taking to Taiwan.——这是我要带去台湾的当地纪念品。
3、Do you have anything to declare?——是否有任何东西需要申报?
4、Do you have any liquor or cigarettes?——你有携带任何酒类或香烟吗? No, I don‘t.——没有。
5、Yes, I have two bottles of whisky.——是的,我带了两瓶酒。
6、Please open this bag.——请打开这个袋子。
7、The camera is for my personal use.——这个相机是我私人使用的。
8、What are these?——这些东西是做何用?
9、You‘ll have to pay duty on this.——你必须为这项物品缴付税金。
10、These are for my personal use.——这些是我私人使用的东西。
11、Do you have any other baggage?——你还有其它行李吗?
12、These are gifts for my friends.——这些是给朋友的礼物。
13、O.K. Please give this declaration card to that officer at the exit.——好了!请将这张申报卡交给出口处的官员。
作者:aehyok
出处:http://www.cnblogs.com/aehyok/
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,那不妨点个推荐吧,谢谢支持:-O。