21

I have a simple LINQ-expression like:

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

The problem is, GetDocument() could throw an exception. How can I ignore all doc-elements where GetDocument(doc.Key) == null or throws an exception?

The same code in old school looks like:

foreach (var doc in allDocs)
{
    try
    {
        if (GetDocument(doc.Key) != null) newDocs.Add(doc);
    }
    catch (Exception)
    {
        //Do nothing...
    }
}
Andrew Hillier
  • 137
  • 1
  • 9
Rocco Hundertmark
  • 545
  • 2
  • 7
  • 20
  • possible duplicate of [Is it possible to handle exceptions within LINQ queries?](http://stackoverflow.com/questions/1294251/is-it-possible-to-handle-exceptions-within-linq-queries) – Narkha Sep 27 '13 at 10:21

5 Answers5

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

I'm not sure it's possible using query comprehension syntax, except via some baroque atrocity like this:

newDocs = (from doc in allDocs
           where ((Predicate<Document>)(doc_ => {
               try {
                   return GetDocument(doc_.Key) != null;
               } catch {
                   return false;
               }
           }))(doc)
           select doc).ToList();
Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
20

A linq extension can be written to skip all elements that cause an 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;
                }
            }
        }
    }

Example:

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

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

posting this here in case anyone else finds this answer first.

Community
  • 1
  • 1
katbyte
  • 2,665
  • 2
  • 28
  • 19
14

You can move the whole try catch block and GetDocument call to another method

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

and then use this function in your query -

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

This will keep your query concise and easy to read.

Unmesh Kondolikar
  • 9,256
  • 4
  • 38
  • 51
4

Have you tried the 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

Yack
  • 1,400
  • 1
  • 10
  • 13
1

Write your own method. MyGetDocument( ) that will handle the exception and call it from LINQ.

newDocs = (from doc in allDocs
       where MyGetDocument(doc.Key) != null
       select doc).ToList();
Itay Karo
  • 17,924
  • 4
  • 40
  • 58