[转载]写出优雅简明代码的论题集 — Csharp(C#)篇[1] – 喜乐的ASP.NET(Alex Song) – 博客园.
最近和一些朋友讨论如何写出优雅的代码,我们都很喜欢C#,所以以C#为例。主要一共有三位程序员在一起讨论,为简单起见我用ABC代表我们三个人。
有时候我们会针对一些代码进行讨论,有时候我们会提出一些观点,有时候我们会一起学习网上一些现有的博客,为了便于大家引用,我给每一个论题都编上号。
在很多情况下,我们的意见统一,那么我会给大家呈现我们的结论;但是有些情况我们有分歧。
你可以加入我们的讨论,我非常也希望能够获知你的意见,让我们一起茁壮成长!
好吧,让我们今天就开始。
论题一:函数越小越好!
相信绝大部分程序员会认同这一点,维护一个超过100行的函数会让人抓狂。
我记得我以前修改过一个用cobol写的程序,一个文件超过10万行,我为了进行一个极其小的修改花了3天的时间,而且最后自己也不知道会不会造成什么严重的后果。– 这已经过去8年了,希望那段代码运行良好。
到底理想状态下,我们的函数应该不大于多少行?我们三个人的答案是:
A: 10 行
B: 15 行
C: 20 行
论题二:用 Linq 简化代码
Linq有时可以帮助我们写出一些非常“人性”的语句。
下面的这个函数是用于在数据库中插入新的评论:
public static void Create(IEnumerable<CommentData> Comments, SqlConnection cn) { // validate params if ( null == cn) throw new ArgumentNullException( "cn" ); if (cn.State != ConnectionState.Open) throw new ArgumentException( "Invalid parameter: connection is not open." , "cn" ); if ( null == Comments) throw new ArgumentNullException( "Comments" ); foreach (CommentData data in Comments) { if (data.CommentId.HasValue) throw new ArgumentNullException( "Create is only for saving new data. Call save for existing data." , "data" ); } .... |
其中foreach这一部分可以简化为:
if (Comments.Any(data => data.CommentId.HasValue)) { throw new ArgumentNullException( "Create is only for saving new data. Call save for existing data." , "data" ); } |
在这一点上,我们存在分歧,A认为没有必要进行简化,因为原来的已经很明确了;但B认为简化后的代码可读性更强,看上去更加直接。
希望每个人都已经知道C#的这个用法了,直接上一些代码:
3.1
原始代码:
List< int > idsToFind = new List< int >(); idsToFind.Add(1); idsToFind.Add(2); |
修改后:
List< int > idsToFind = new List< int > {1, 2}; |
3.2
原始代码:
var startingPoint = new Point(); startingPoint.X = 5; startingPoint.Y = 13; |
修改后:
var startingPoint = new Point() { X = 5, Y = 13 }; |
论题四:运用 ?:和??
据说,有些公司会拿这个来测试入门的程序员:
4.1
原始代码:
if (c != null ) System.Console.WriteLine(c.Name); else System.Console.WriteLine( "List element has null value." ); |
修改后:
System.Console.WriteLine(c != null ? c.Name : "List element has null value." ); |
4.2
原始代码:
string name = value; if (value == null ) { name = string .Empty; } |
修改后:
string name = (value != null ) ? value : string .Empty; |
还可以更简单,变成:
string name = value ?? string .Empty; |
论题五: 运用AS
原始代码:
if (employee is SalariedEmployee) { var salEmp = (SalariedEmployee)employee; pay = salEmp.WeeklySalary; // ... } |
修改后:
var salEmployee = employee as SalariedEmployee; if (salEmployee != null ) { pay = salEmployee.WeeklySalary; // ... } |
论题六: 运用 using
using首次出现是在visual studio 2005 中,在这以前,很多程序员晕倒在了释放资源的逻辑中。
使用using语句实际上生成的IL代码中是一个try, finally代码块,在finally代码块里释放资源。
原始代码:
public IEnumerable<Order> GetOrders() { var orders = new List<Order>(); var con = new SqlConnection( "some connection string" ); var cmd = new SqlCommand( "select * from orders" , con); var rs = cmd.ExecuteReader(); while (rs.Read()) { // ... } rs.Dispose(); cmd.Dispose(); con.Dispose(); return orders; } |
这是一段非常丑陋的代码,我们完全迷失在dispose群中,什么时候要调用哪个dispose啊? 天哪? 如果我们用 finally, 可以将代码写为:
public IEnumerable<Order> GetOrders() { SqlConnection con = null ; SqlCommand cmd = null ; SqlDataReader rs = null ; var orders = new List<Order>(); try { con = new SqlConnection( "some connection string" ); cmd = new SqlCommand( "select * from orders" , con); rs = cmd.ExecuteReader(); while (rs.Read()) { // ... } } finally { rs.Dispose(); cmd.Dispose(); con.Dispose(); } return orders; } |
看看using到底给我们带来了什么:
public IEnumerable<Order> GetOrders() { var orders = new List<Order>(); using ( var con = new SqlConnection( "some connection string" )) { using ( var cmd = new SqlCommand( "select * from orders" , con)) { using ( var rs = cmd.ExecuteReader()) { while (rs.Read()) { // ... } } } } return orders; |
好多了,对吗? 完全不用再用那一堆的try/finally 代码了,也不用使用一堆的null,为了使代码更轻巧,让我们再做小小修改:
public IEnumerable<Order> GetOrders() { var orders = new List<Order>(); using ( var con = new SqlConnection( "some connection string" )) using ( var cmd = new SqlCommand( "select * from orders" , con)) using ( var rs = cmd.ExecuteReader()) { while (rs.Read()) { // ... } } return orders; } |