2010-12-01 6 views
13

J'ai simple LINQ expression comme:Gestion des exceptions dans une expression LINQ

newDocs = (from doc in allDocs 
     where GetDocument(doc.Key) != null 
     select doc).ToList(); 

Le problème est, GetDocument() pourrait lancer une exception. Comment puis-je ignorer tous les éléments doc où GetDocument (doc.Key) == null ou déclenche une exception?

Le même code dans la vieille école ressemble à:

foreach (var doc in allDocs) 
      { 
       try 
       { 
        if (GetDocument(doc.Key) != null) newDocs.Add(doc); 
       } 
       catch (Exception) 
       { 
        //Do nothing... 
       } 
      } 
+0

double possible de [Est-il possible de gérer les exceptions dans les requêtes LINQ?] (Http://stackoverflow.com/questions/1294251/is-it-possible-to-handle-exceptions-within-linq-queries) – Narkha

Répondre

13
allDocs.Where(doc => { 
    try { 
     return GetDocument(doc.Key) != null; 
    } catch { 
     return false; 
    } 
}).ToList(); 

Je ne suis pas sûr qu'il est possible en utilisant la syntaxe de compréhension de requête, sauf par une atrocité baroque comme ceci:

newDocs = (from doc in allDocs 
      where ((Predicate<Document>)(doc_ => { 
       try { 
        return GetDocument(doc_.Key) != null; 
       } catch { 
        return false; 
       } 
      }))(doc) 
      select doc).ToList(); 
+0

La première partie fonctionne parfaitement. Je pensais qu'il y avait un moyen plus court d'utiliser sans essayer/attraper. Mais ça marche et ça a l'air bien.Thanx beaucoup –

11

Vous pouvez déplacer l'ensemble du bloc try catch et l'appel GetDocument à une autre méthode

Document TryGetDocument(string key) 
{ 
     try 
     { 
      if (GetDocument(doc.Key) != null) 
       return doc; 
     } 
     catch (Exception) 
     { 
      return null; 
     } 
    return null; 
} 

puis utilisez cette fonction dans votre requête -

newDocs = (from doc in allDocs 
     where TryGetDocument(doc.Key) != null 
     select doc).ToList(); 

Cela permet de garder votre requête concise et facile à lire.

+1

+1: pour TryGetXXX Pattern, je l'aime personnellement tout en écrivant le code de gestion des exceptions. – TalentTuner

1

Écrivez votre propre méthode. MyGetDocument() qui gérera l'exception et l'appellera depuis LINQ.

newDocs = (from doc in allDocs 
     where MyGetDocument(doc.Key) != null 
     select doc).ToList(); 
3

Avez-vous essayé le Expression.TryCatch

IEnumerable<string> allDocs = new List<string>(); 
var newDocs = (from doc in allDocs 
        where Expression.TryCatch(
          Expression.Block(GetDocument(doc.key)), 
          Expression.Catch(typeof(Exception),null)) != null         
          select doc).ToList(); 

TryExpression msdn

10

Une extension LINQ peut être écrit pour sauter tous les éléments qui provoquent une exception. See this stackoverflow post

public static IEnumerable<T> CatchExceptions<T> (this IEnumerable<T> src, Action<Exception> action = null) { 
     using (var enumerator = src.GetEnumerator()) { 
      bool next = true; 

      while (next) { 
       try { 
        next = enumerator.MoveNext(); 
       } catch (Exception ex) { 
        if (action != null) { 
         action(ex); 
        } 
        continue; 
       } 

       if (next) { 
        yield return enumerator.Current; 
       } 
      } 
     } 
    } 

Exemple:

ienumerable.Select(e => e.something).CatchExceptions().ToArray() 

ienumerable.Select(e => e.something).CatchExceptions((ex) => Logger.Log(ex, "something failed")).ToArray() 

posté cette ici au cas où quelqu'un d'autre trouve cette réponse première.