在LINQ表达式中的异常处理

22

我有一个简单的LINQ表达式,如下:

newDocs = (from doc in allDocs
           where GetDocument(doc.Key) != null
           select doc).ToList();
问题在于,GetDocument() 可能会抛出异常。如何忽略所有 GetDocument(doc.Key) 等于 null 或抛出异常的文档元素?
老式代码如下:
foreach (var doc in allDocs)
{
    try
    {
        if (GetDocument(doc.Key) != null) newDocs.Add(doc);
    }
    catch (Exception)
    {
        //Do nothing...
    }
}

可能是在LINQ查询中处理异常的方法的重复问题。 - Narkha
5个回答

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

我不确定是否可以使用查询理解语法实现,除非通过类似于这样的古怪恶行:

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

20

可以编写一个 Linq 扩展来跳过所有导致异常的元素。请参考此 StackOverflow 帖子

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

示例:

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

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

在这里发布这个答案,以防其他人先找到。


14

你可以将整个 try catch 块和 GetDocument 调用移动到另一个方法中。

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

然后在查询中使用此函数 -

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

这将使您的查询简明扼要且易于阅读。


4

您尝试过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


1
编程相关内容:编写自己的方法MyGetDocument( ),处理异常并从LINQ中调用它。
newDocs = (from doc in allDocs
       where MyGetDocument(doc.Key) != null
       select doc).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接