標籤:reg linq yield 無效 sele 運用 應用 不必要 select
建議31:在LINQ查詢中避免不必要的迭代
無論是SQL查詢還是LINQ查詢,搜尋到結果立刻返回總比搜尋完所有的結果再將結果返回的效率要高。
範例程式碼:
class MyList : IEnumerable<Person> { //為了示範需要,類比了一個元素集合 List<Person> list = new List<Person>() { new Person(){ Name = "Mike", Age = 20 }, new Person(){ Name = "Mike", Age = 30 }, new Person(){ Name = "Rose", Age = 25 }, new Person(){ Name = "Steve", Age = 30 }, new Person(){ Name = "Jessica", Age = 20 } }; /// <summary> /// 迭代次數屬性 /// </summary> public int IteratedNum { get; set; } public Person this[int i] { get { return list[i]; } set { this.list[i] = value; } } #region IEnumerable<Person> 成員 public IEnumerator<Person> GetEnumerator() { foreach (var item in list) { //每遍曆一個元素就加1 IteratedNum++; yield return item; } } #endregion #region IEnumerable 成員 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } class Person { public string Name { get; set; } public int Age { get; set; } }
針對上述集合,返回年齡等於20的第一個元素。下面有兩個查詢模式,我們來考慮哪一個效率更高。
//第一種var temp = (from c in list where c.Age == 20 select c).ToList();//第二種var temp2 = (from c in list where c.Age >= 20 select c).First();
通常我們會認為第一種的效率會更高一些,因為它似乎返回的就是等於20的那兩個元素,而第二種模式則需要查詢所有大於等於20的元素。實際上並不是這樣的。看下面測試代碼:
MyList list = new MyList(); var temp = (from c in list where c.Age == 20 select c).ToList(); Console.WriteLine(list.IteratedNum.ToString()); list.IteratedNum = 0; var temp2 = (from c in list where c.Age >= 20 select c).First(); Console.WriteLine(list.IteratedNum.ToString());
輸出:
5
1
注意:第二次查詢僅僅迭代1次,因為20正好在List的首位。First方法實際完成的工作是:搜尋到滿足條件的第一個元素,就從集合返回。如果一個集合包含了很多元素,那麼這種查詢會為我們帶來可觀的時間效率。
與First方法類似的還有Take方法,Take方法接收一個整型參數,然後我們返回該參數指定的個數。與First一樣,它在滿足條件後,會從當前的迭代過程中直接返回,而不是等待整個迭代過程完畢再返回。如果一個集合包含了很多的元素,那麼這種查詢會為我們帶來可觀的時間效率。
注意下面的例子:
MyList list = new MyList(); var temp = (from c in list select c).Take(2).ToList(); Console.WriteLine(list.IteratedNum.ToString()); list.IteratedNum = 0; var temp2 = (from c in list where c.Name == "Mike" select c).ToList(); Console.WriteLine(list.IteratedNum.ToString());
輸出為:
2
5
雖然LINQ查詢的最後的結果都是返回兩個元素“Mike”對象,但是,實際上,使用Take方法僅僅為我們迭代了2次,而使用where查詢方式帶來的卻是整個集合的迭代。
在實際編碼過程中,要充分運用First和Take等方法,這樣才能為我們的應用帶來高效性,而不會讓時間浪費在一些無效的迭代中。
轉自:《編寫高品質代碼改善C#程式的157個建議》陸敏技
【轉】編寫高品質代碼改善C#程式的157個建議——建議31:在LINQ查詢中避免不必要的迭代