最近筆者看到了一篇文章介紹javascript如何寫出更好的條件判斷,發現其中的用法,自己一路走來也不自覺都用上了,這些方式並不侷限於javascript,本篇就用C#來示範,不僅讓可讀性變高,自己看起來也更順眼了。
用陣列是否包含取代逐一判斷
某次需要權限判斷時,因為系統不複雜,所以身分和權限是用常數定義在程式內,為了凸顯用陣列的好處,先用瑣碎的方式來判斷:
const int ADMIN = 1; const int MANAGER = 2; const int USER = 3; const int ACTION_1 = 1; const int ACTION_2 = 2; const int ACTION_3 = 3; const int ACTION_4 = 4; const int ACTION_5 = 5; const int ACTION_6 = 6; //依據身分判斷動作是否允許 //原始作法,個別判斷 if(permission == USER){ if(action == ACTION_4 || action == ACTION_5 || action == ACTION_6){ //允許執行動作 } }
這方式用起來很瑣碎,要新增允許的動作時,也很難維護,改寫成陣列方式試試
//先將各身分的動作定義好 int[] ADMIN_ACTIONS = new int[]{ ACTION_1, ACTION_2, ACTION_3, ACTION_4, ACTION_5, ACTION_6 }; int[] MANAGER_ACTIONS = new int[]{ ACTION_2, ACTION_3, ACTION_4, ACTION_5, ACTION_6 }; int[] USER_ACTIONS = new int[]{ ACTION_4, ACTION_5, ACTION_6 }; //直接使用陣列方法是否包含 if(permission == USER && USER_ACTIONS.Contains(action)){ //允許執行動作 }
修改後相對簡便許多,日後增加動作直接添加在陣列內就好了
用map取代switch
承上例,可以再進一步改進,連身分也不需要判斷,如果高權限包含低權限,可以進一步優化
//各身分的動作可以向前包含,並且增減不需要額外修改 int[] USER_ACTIONS = new int[] { ACTION_4, ACTION_5, ACTION_6 }; int[] MANAGER_ACTIONS = USER_ACTIONS.Concat(new int[] { ACTION_2, ACTION_3 }).ToArray(); int[] ADMIN_ACTIONS = MANAGER_ACTIONS.Concat(new int[] { ACTION_1 }).ToArray(); Dictionary<int, int[]> PERMISSION = new Dictionary<int, int[]>() { { ADMIN, ADMIN_ACTIONS }, { MANAGER, MANAGER_ACTIONS }, { USER, USER_ACTIONS }, }; if (PERMISSION[permission].Contains(action)) { //允許執行動作 }
和一開始的例子做比較,可讀性和可維護性都大大提升了許多,當初能想到這樣改良,其實也是一個習慣,當你在做重複的動作時,就代表那些動作可以找出規律統整起來,多花點心思,就可以改善許多。
提早return,減少分支
在多層if判斷時,會長出許多if else,太多層時就難以讀取或維護,萬一未來更改條件時,改錯層,就埋下bug了
public string function HaveAdminPermission(){ if(has_login){ if(permission == ADMIN){ if(action == ACTION_1){ return "允許執行動作"; }else{ return "wrong action"; } }else{ return "not admin"; } }else{ return "not login"; } }
上方的例子,看起來像千層麵一樣,如果可以減少層數,那接手的人或者未來自己失憶時也比較快理解
public string function HaveAdminPermission(){ if(!has_login){ return "not login"; } if(permission != ADMIN){ return "not admin"; } if(action != ACTION_1){ reutrn "wrong action"; } return "允許執行動作"; }
如此少了許多層的else,條件看起來清晰易懂,簡化成一層,維護性大提升~
判斷全部符合或部分符合
以往這類型的判斷,都是要使用迴圈,但C#的LINQ大大簡化了這部分
class Book { public string Name { get; set; } public string Type { get; set; } } var array = new Book[] { new Book(){Name = "a", Type = "novel"}, new Book(){Name = "b", Type = "novel"}, new Book(){Name = "c", Type = "novel"} }; //是否包含名稱b bool have_b = false; for(var item in array){ if(item.Name == "b"){ have_b = true; break; } } //是否全部類型都是novel var all_is_novel = true; for(var item in array){ if(item.Type != "novel"){ all_is_novel = false; } } //改用LINQ判斷 have_b = array.Any(x => x.Name == "b");//True all_is_novel = array.All(x => x.Type == "novel");//True
不得不說,現在寫C#,不用LINQ渾身不對勁,畢竟太方便了,一行搞定以前需要好幾行的事,但是要注意別走火入魔,真的沒法簡化的,或是破壞可讀性的,還是用傳統方式好。
null條件運算子
有時候null的判斷,真心煩人,不判斷又會有exception,但每次判斷又覺得做重複的事,這事早已經在C# 6.0之後被解決了,是不是很方便呢~
Book book = null; string name = null; if(book != null && book.Name != null){ name = book.Name; } else{ name = string.Empty; } //簡化取值的判斷 name = book?.Name;//null //簡化預設值的設置,若是null則為string.Empty name = book?.Name ?? string.Empty;
參考
發表迴響