1. 程式人生 > >在Linq的Where條件中,如何優雅的進行型別轉換?

在Linq的Where條件中,如何優雅的進行型別轉換?

大家應該都知道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();