Where 方法的一個簡單實作,下面将其添加 Where1 方法的實作中,檢查 source和 predicate 參數是否為null:
public static IEnumerable<T> Wherel<T>(this IEnumerable<T> source, Func<T,bool> predicate){ if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate));
foreach (T item in source) { if (predicate(item)) { yield return item; } }}
編寫代碼測試 ArgumentNullException,定義預處理語句 #line,以從源代碼行 1000開始。在第 1004 行中沒有發生異常,其中 null 傳遞給 Where1 方法;相反,在第1006 行中包含的 foreach 語句發生了異常。延遲發現這個的原因是,在方法 Where1的實作中,延遲執行了 yield 語句。
private static void YieldSampleSimple(){#line 1000 Console.WriteLine(nameof(YieldSampleSimple)); try { string[] names = { "James", "Niki", "John", "Gerhard", "Jack" }; var q = names.Wherel(null); foreach (var n in q) // callstack position for exception { Console.WriteLine(n); } } catch (ArgumentNullException ex) { Console.WriteLine(ex); } Console.WriteLine();}
為了解決這個問題,并向調用者更早地提供錯誤資訊,Where1 方法通過 Where2 方法在兩個部分實作。這裡,Where2 方法隻檢查不正确的參數,不包括 yield 語句。使用 yield return 的實作是在一個單獨的私有方法 WhereImpl 中完成的。在檢查輸入參數之後,從 Where2 方法中調用此方法。
public static IEnumerable<T> Where2<T>(this IEnumerable<T> source, Func<T, bool> predicate){ if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); return Where2Impl(source, predicate);}private static IEnumerable<T> Where2Impl<T>(IEnumerable<T> source, Func<T, bool> predicate){ foreach (T item in source) { if (peedicate(item)) { yield return item; } }}
private static void YieldSampleWithPrivateMethod() {#line 1000 Console.WriteLine(nameof(YieldSampleWithPrivateMethod)); try { string[] names = { "James", "Niki", "John", "Gerhard", "Jack" }; var q = names.Where2(mull); // callstack position for erception foreach (var n in q) { Console.WriteLine(n); }}catch (ArgumentNullException ex){ Console.WriteLine(ex); } Console.WriteLine();}
public static IEnumerable<T> Where3<T>(this IEnumerable<T> source, Func<T,bool> predicate){ if (source == null) throw new ArgumentNullException (nameof (source)); if (predicate == null) throw new ArgumentNullException (nameof (predicate)); return Iterator(); IEnumerable<T> Iterator() { foreach (T item in source) { if (predicate(item)) { yield return item; } } }}