2016-02-11 9 views
5

は、コード例である:今クロージャ内で例外がキャッチされなかったのはなぜですか?ここ

public IList<LogEntry> ReadLogs(Guid id, string name) 
    { 
     var logs = this.RetrieveLogs(id, name); 

     if (logs != null) 
     { 
      foreach (LogEvent logEvent in logs) 
      { 
       // bla, bla, bla 
      } 
     } 

     return logEntries; 
    } 

    private IEnumerable<LogEvent> RetrieveLogs(Guid id, string name) 
    { 
     try 
     { 
      FilterCriteria filterCriteria = CreateFilterCriteria(); 
      return (from log in this.loggingProvider.ReadLogs(filterCriteria, 1) 
        where log.ParticipantObjects[0].ParticipantObjectId == id.ToString() 
        && log.LogEventParameters[0].Value == name 
        orderby log.Timestamp.ToLocalTime() descending 
        select log).AsEnumerable(); 
     } 
     catch (Exception ex) 
     { 
      this.tracer.Write(Category.Error, ex, "Error"); 
      return null; 
     } 
    } 

例外がloggingProvider.ReadLogs()方法の内側にあった場合、それは捕捉され追跡されます。しかし、たとえば、ParticipantObjects[0]がない場合、この例外はここでは捕捉されず追跡されません。それはラムダ式とクロージャーと関係があるようです。

説明は何ですか?

+1

あなたが何かを行うまでクエリが実行されません。 – user1666620

答えて

5

loggingProvider.ReadLogsRetrieveLogsの中で実行されます。しかし、他のすべてのラムダは、外側のthis.ReadLogsで反復処理するときにのみ実行されます。

したがって、例外は上位のメソッドでスローされるため、RetrieveLogsの中にキャッチすることはできません。

クエリが実際に返す前に実行されていることを確認するためにToList()またはToArray()AsEnumerableを変更、これを回避します。

3

IEnumerable LINQクエリの結果は、列挙されたときにのみ評価されます。

あなたが期待するところExceptionがスローされるようにするために、あなたはToList()のような、関連する拡張メソッドのいずれかを使用してLINQクエリの結果IEnumerableを列挙する必要があります。サイドノート(レネ・フォークトからの借入)として、あなたは、次のようにExceptionはあなたのLINQを書き込むことによってスローされるのを避けることができ

return this.loggingProvider.ReadLogs(filterCriteria, 1).Where(log => 
    log.ParticipantObjects.FirstOrDefault() != null && 
    log.ParticipantObjects[0].ParticipantObjectId == id.ToString() && 
    log.LogEventParameters[0].Value == name).OrderBy(log => 
    log.Timestamp.ToLocalTime()).ToList(); 
+0

いいえ、それは私が意味するものではありません。私はそれを書いただけで、クエリ言語より読みやすくなりました。私は 'AsEnumerable()'を 'ToList()'や 'ToArray()'のようなクエリに変更しない限り、結果は同じだと思います。 –

+0

本当に簡単です。私のポイントは、 'ParticipantObjects [0]'が存在するかどうかのチェックのために、 'NullReferenceException'や' IndexOutOfRangeException'を生成しない余分な条件です。 – toadflakz

+0

したがって、 'log.ParticipantObjects.First()!= null'を' log.ParticipantObjects.FirstOrDefault()!= null'に変更したい場合は、選択が空の場合は 'First'がスローされます); –

15

私は前にそれを言っていると私は間違いなく再びそれを言うだろう:をクエリについて知るのに最も重要なことは、クエリは質問であり、クエリの答えではなく、です。

作成したクエリオブジェクトは、構築するだけでは実行されません。あなたは質問を構築しています。クエリーを実行するまで、に質問があり、と表示されます。実行はtryブロックの外側です。

+0

あなたはすでに何が起こったかを仮定しているので、質問を作成したり実行したりしなかったということだけを言いましょう。私はバグを作り出した他の人のコードを分析していました。私は既にあなたがここで述べたことを知っていましたが、ToListではなくAsEnumerableであることに気付かず、何らかの理由でClosureを含むいくらかの最適化をしていると仮定しました。 –

+0

@NenadDobrilovic:さて、第2段落の「あなた」のために「他の誰か」を精神的に代用してください。クエリが実行されなかったことに気付かずにエラーを見つけられたことをうれしく思っています。将来的にはそれを作る可能性は低いですし、コード内のロジックエラーがどこにあるのかわかりました。実際には1つがある場合。 –

関連する問題