1. 程式人生 > 實用技巧 >編寫高質量程式碼改善C#程式的建議(Day2)

編寫高質量程式碼改善C#程式的建議(Day2)

建議18:foreach不能代替for

在foreach迴圈內部不支援對集合進行增刪操作,FCL提供的迭代器內部維護了一個對集合版本的控制,增刪操作都會使版本號加1,foreach實現中呼叫MoveNext方法時會對版本號進行檢測,如果檢測到版本號有變動則會丟擲InvalidOperationException異常。

建議19:使用更有效的物件和集合初始化

Person person = new Person(){Name = "Lance", Age = 23};
List<Person> personList = new List<Person>()
{
    
new Person(){Name = "Jimmy", Age = 35}, person, null };

省略了通過構造方法傳值的步驟,但是初始化設定項更重要的作用是為LINQ查詢中的匿名型別進行屬性的初始化。LINQ查詢返回的集合中匿名型別的屬性都是隻讀的,如果需要為匿名型別屬性賦值只能通過初始化設定項來進行。

var pTemp = from p in personList select new { p.Name,AgeScope = p.Age > 20 ? "Old" : "Young" };

建議20:使用泛型集合代替非泛型集合

ArrayList不是型別安全的,並且效率上沒有List<T>高效。

建議21:選擇正確的集合

如果集合的數目固定並且不涉及轉型,使用陣列效率高,否則使用List<T>。

直接儲存指的是該型別的集合資料元素可以直接通過下標來訪問,新增元素直接把資料放在集合末尾就行了,插入元素就比較低效了,需要移動元素。

順序儲存無法通過下標索引查詢,它是通過對地址的引用來搜尋元素的,為了找到某個元素必須遍歷所有元素,優點是插入和刪除資料效率高。

建議22:確保集合的執行緒安全

在多執行緒應用環境下,可以通過Lock來保證執行緒安全,也可以使用Concurrent下的相關執行緒安全集合類。

建議25:謹慎集合屬性的可寫操作

如果類中有集合屬性,那麼應該保證屬性物件是由型別本身產生的,而不是外部直接賦值,在不知情情況下對外部引用物件修改時會影響到類中集合屬性,可以使集合屬性保持只讀,然後通過構造方法或者其他方式傳遞資料新增到集合屬性中。

建議26:使用匿名型別Var儲存LINQ查詢結果

匿名型別由var、賦值運算子、非空初始值組成(var x = null 會報錯)

匿名型別的屬性是隻讀的,沒有屬性設定器,一旦初始化就不可更改(指通過LINQ關鍵字查詢new出來的匿名型別);

如果兩個匿名型別的屬性值相同,那麼就認為兩個匿名型別相等;

實際開發中需求總是變化,需要根據需求建立很多臨時型別,如果都用普通自定義型別的話會增加程式碼量並且難以維護,匿名型別可以很好的解決這個問題。匿名型別預設過載ToString方法輸出型別的屬性名及對應的值。

建議27:在查詢中使用Lambda表示式

任何LINQ查詢都能通過呼叫擴充套件方法的方式來替代,針對LINQ設計的擴充套件方法大多應用了泛型委託。

Action用於執行一個操作沒有返回值;Func用於執行一個操作並返回值;Predicate用於定義一組條件並判斷引數是否符合條件;

// 把lambda寫在foreach查詢裡面不會影響效率,因為這是延遲求值,對查詢結果的訪問每次都會執行計算
foreach(var p in personList.Where(person=>person.CompanyID<20))
{
    Console.WriteLine(p.PersonName);
}

建議28:理解延遲求值和主動求值之間的區別

List<int> list = new List<int>(){ 0,1,2,3,4,5,6,7,8,9};
var temp1 = from c in list where c>5 select c;
var temp2 = (from c in list where c>5 select c).ToList<int>();
list[0] = 11;
//查詢temp1時會計算linq的值,而temp2是立即執行的,所以修改list[0]對temp2已經沒有影響了

建議29:區別LINQ查詢中的IEnumerable<T>和IQueryable<T>

查詢本地資料來源用IEnumerable<T>,遠端資料來源用IQueryable<T>

AsEnumerable<T>也是延遲查詢,只不過是把遠端資料轉化成本地資料

DataContext ctx = new DataContext("server=192.168.1.84;database=IMS;uid=sa;pwd=123");
Table<TabStandard> standards = ctx.GetTable<TabStandard>();
var temp1 = (from s in standards where s.AvgPressure > 40 select s).AsEnumerable<TabStandard>();
var temp2 = from s in temp1 where s.RatePr > 0.8 select s;
foreach (var item in temp2)
{  
  Console.WriteLine(item.Indent.ToString() + " " + item.AvgPressure.ToString() + " " + item.RatePr.ToString());
}

在IQueryable<T>查詢的時候,無法使用自定義的方法,會拋異常

var temp3 = from s in standards where PressureLimit(s.AvgPressure) select s;
// 丟擲NotSupportedException異常

如果換成一個IEnumerable<T>查詢則不會

var temp3 = from s in temp1 where PressureLimit(s.AvgPressure) select s;

建議30:使用LINQ取代集合中的比較器和迭代器

var orderByBaseSalary = from s in companySalary orderby s.BaseSalary select s;