2016-02-11 8 views
5

Oto przykładowy kod:Dlaczego wyjątek nie został złapany w zamknięciu?

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

Teraz, jeśli nie był wyjątkiem wewnątrz loggingProvider.ReadLogs() metody, zostanie złapany i prześledzić. Ale jeśli, na przykład, nie ma ParticipantObjects[0], ten wyjątek nie zostanie tutaj przechwycony i wyśledzony. Wydaje się, że ma to coś wspólnego z wyrażeniami lambda i zamknięciami.

Jakie jest wytłumaczenie?

+1

zapytanie nie jest uruchamiane, dopóki coś z nim nie zrobisz – user1666620

Odpowiedz

5

loggingProvider.ReadLogs jest wykonywany wewnątrz RetrieveLogs. Ale wszystkie inne lambdy są wykonywane tylko wtedy, gdy wykonujesz iterację nad nimi w zewnętrznym this.ReadLogs.

Wyjątek jest zgłaszany w górnej metodzie, więc nie można go przechwycić wewnątrz RetrieveLogs. Aby uniknąć tego, zmień AsEnumerable na ToList() lub ToArray(), aby upewnić się, że zapytanie jest faktycznie wykonywane przed zwróceniem.

3

Wynik z zapytania LINQ jest oceniany tylko wtedy, gdy jest wyliczony.

Aby wykonać rzutowanie według Exception, należy wyliczyć wynik zapytania LINQ IEnumerable, używając jednej z odpowiednich metod rozszerzenia, takich jak ToList().

Jako marginesie (udzielanie od Rene Vogt) można uniknąć Exception wyrzucane przez pisanie LINQ w następujący sposób:

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

Nie, nie o to mi chodziło. Po prostu napisałem to w ten sposób, ponieważ łatwiej mi to odczytać niż język zapytań. Myślę, że wynik jest taki sam, o ile nie zmienisz wartości 'AsEnumerable()' na coś, co wykonuje zapytanie takie jak 'ToList()' lub 'ToArray()'. –

+0

To naprawdę jest łatwiejsze. Chodzi mi o to, że dodatkowy warunek nigdy nie wygeneruje 'NullReferenceException' lub' IndexOutOfRangeException' z powodu sprawdzenia, czy istnieje 'ParticipantObjects [0]'. – toadflakz

+0

Więc możesz chcieć zmienić 'log.ParticipantObjects.First()! = Null' na' log.ParticipantObjects.FirstOrDefault()! = Null', ponieważ 'First' wyrzuca, jeśli wybór jest pusty;) –

15

Powiedziałem to wcześniej i będę bez wątpienia powiedzieć to jeszcze raz: Najważniejsze, aby wiedzieć o zapytaniu jest to, że zapytanie jest pytaniem, a nie odpowiedzią na pytanie:.

Obiekt zapytania, który zbudowałeś, nie jest wykonywany tylko przez jego zbudowanie. Budujesz pytanie. To pytanie nie jest w stanie odpowiedzieć na pytanie: : i , dopóki nie zostanie wykonane zapytanie. A wykonanie jest poza blokiem try.

+0

Ponieważ już założyłeś, co się stało, pozwól mi tylko powiedzieć, że nie zbudowałem ani nie wykonałem kwerendy, analizowałem tylko czyjś inny (tutaj jest znacznie uproszczony) kod, który spowodował błąd.Chociaż już wiedziałem, co tu napisałeś, po prostu nie zauważyłem, że było to pod koniec tego wyciągu, a nie z ToLista iz jakiegoś powodu, założyłem, że to była dziwna optymalizacja z zamknięciami. –

+0

@NenadDobrilovic: Więc, w drugim akapicie, zastąp mentalnie "ktoś inny" dla "ciebie". Cieszę się, że wymyśliłeś swój błąd - nie zauważając, że zapytanie nie zostało wykonane - i dlatego jest mniej prawdopodobne, że uda się to zrobić w przyszłości, i cieszę się, że znalazłeś błąd logiczny w kodzie, jeśli w rzeczywistości taki istnieje. –