天天看點

C# 本地函數與yield語句

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;      }    }  }}