文章目錄
- 論題一:函數越小越好!
- 論題二:用 Linq 簡化代碼
- 論題四:運用 ?:和??
- 論題五: 運用AS
- 論題六: 運用 using
最近和一些朋友討論如何寫出優雅的代碼,我們都很喜歡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; // ...}
論題六: 運用 usingusing首次出現是在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;}
未完待繼…相關閱讀:寫出優雅簡明代碼的論題集 -- Csharp(C#)篇[2]