在Linq的Where條件中,如何優雅的進行型別轉換?
阿新 • • 發佈:2019-01-12
大家應該都知道Int32.Parse()是不安全,但有時可能會有僥倖心理,而我正是在這樣的心理驅使下,這麼幹了。相關場景簡化處理後的程式碼,如下。
List<BookInfo> bookLst = new List<BookInfo>(); for (var i = 0; i < 100000000; i++) { bookLst.Add(new BookInfo() { Num = i.ToString() }); } //原有寫法 var finalBookLst1= bookLst.Where(p => Int32.Parse(p.Num) > 10).ToList(); public class BookInfo { public string Num { get; set; } }
很顯然,在linq的where條件之中,直接進行型別轉換是不安全的,基於此我們需要對這段程式碼進行優化。
既然是對集合進行操作,那麼我們可以使用for迴圈,來替代原有的where條件,因此便有了下面一段程式碼。
var finalBookLst2= new List<BookInfo>(); for (var j = 0; j < bookLst.Count; j++) { int num1; Int32.TryParse(bookLst[j].Num,out num1); if (num1 > 10) finalBookLst2.Add(bookLst[j]); }
在上述程式碼中,我們直接遍歷集合中的每一個物件,對其進行業務判斷後,將滿足條件的物件加入到預期結果的集合之中,最後我們便得到了最終的結果。
用for迴圈寫完之後,我的第一想法就是這多low呀,效能得多差呀。於是乎經過了一番百度,我們的第二個方案便產生了。
ConcurrentBag<BookInfo> finalBookLst3 = new ConcurrentBag<BookInfo>(); Parallel.For(0,bookLst.Count,(num)=> { int num2; Int32.TryParse(bookLst[num].Num,out num2); if (num2 > 10) finalBookLst3.Add(bookLst[num]); });
Parallel主要用於任務的並行執行,在上面的示例中,我們將我們業務判斷通過Parallel並行執行,希望能夠優化響應時間。但是,悲催的是,使用Parallel的方案更加耗時。
從以上示例可以看出,並行執行並不一定比序列執行效率高,因為並行執行是有額外開銷。同時需要支出的是,List是執行緒不安全的,因此我們使用ConcurrentBag<T>來儲存處理結果。
而對於bookLst的訪問,由於不存在資源競爭,所以是安全。
木得辦法,由於Parallel效能太差,我們是要捨棄這種方案的,想要替代for迴圈還得另尋它法,最後便有了如下程式碼的產生,這也是我們最終選擇的方案。
private static bool CheckNum(BookInfo bookInfo) { int num; Int32.TryParse(bookInfo.Num, out num); if (num > 10) return true; else return false; } var finalBookLst4 = bookLst.Where(new Func<BookInfo,bool>(CheckNum)).ToList();