iT邦幫忙

0

C# 在迭代器中錯誤捕捉的問題

c#

小弟在練習迭代器時,碰上錯誤處理的問題想請教各位大大。

一開始發現錯誤沒有辦法正確被外層 catch 區塊捕捉,如下

static void Main(string[] args) {
  try {
    IEnumerable<int> a = null;
    var b = DoNothing(a);
  }
  catch (Exception ex) 
  {  }
}

static IEnumerable<TSource> DoNothing<TSource>(IEnumerable<TSource> source) {
  if(source == null) throw new ArgumentNullException();
  using (var iterator = source.GetEnumerator()) {
    while (iterator.MoveNext())
      yield return iterator.Current;
  }
}

無論我怎麼修改內容或重新建置,試了各種蠢方法,程式碼依然不會進到 catch 區塊,而是將錯誤內容放在變數 b 的結果檢視。

後來去找官方 Linq 的 source code,終於找到與我的程式碼不同處了,它型別檢查與錯誤拋出的方法是用 return 而不是 yield return,所以我把迭代器方法抽出,如下

static void Main(string[] args) {
  try {
    IEnumerable<int> a = null;
    var b = DoNothing(a);
  }
  catch (Exception ex)
  {  }
}

static IEnumerable<TSource> DoNothing<TSource>(IEnumerable<TSource> source) {
  if(source == null) throw new ArgumentNullException();
  return DoNothingIterator(source);
}
static IEnumerable<TSource> DoNothingIterator<TSource>(IEnumerable<TSource> source) {
  using (var iterator = source.GetEnumerator()) {
    while (iterator.MoveNext())
      yield return iterator.Current;
  }
}

發現拋出錯誤無法與 yield return 寫在一起,但我想搞清楚原因,所以上來發文求助,希望有大大能開導小弟。

/images/emoticon/emoticon06.gif/images/emoticon/emoticon06.gif

1 個回答

2
暐翰
iT邦大師 1 級 ‧ 2019-03-05 18:46:27
最佳解答

發現拋出錯誤無法與 yield return 寫在一起

可以寫一起

終於找到與我的程式碼不同處了,它型別檢查與錯誤拋出的方法是用 return 而不是 yield return

因為IEnumerable + yield return 等於跟系統宣告說等我用到時在給我資料並執行
而你的問題就出在這,這個技術稱為 lazy evaluation 『意味著在迭代查詢結果之前,不會執行迭代』,假如只有return就不會使用lazy evaluation直接執行迭代。

最簡單迭代查詢結果方式,使用ToList或是ToArray,程式改成下面這樣就可以

static void Main(string[] args) {
  try {
    IEnumerable<int> a = null;
    var b = DoNothing(a).ToList();
  }
  catch (Exception ex)
  {  }
}

米歐 iT邦新手 5 級 ‧ 2019-03-06 13:33:02 檢舉

原來如此,謝謝大大開導。

所以是因為使用 yield return,即便沒有經過這一段程式碼,也會變成 lazy evaluation,連錯誤也需要等待被查詢時才會顯示,我陷在錯誤會馬上傳回的泥沼,再次感謝大大。

/images/emoticon/emoticon41.gif

暐翰 iT邦大師 1 級 ‧ 2019-03-06 14:08:47 檢舉

/images/emoticon/emoticon12.gif

我要發表回答

立即登入回答