3

我在用着 ...

tmpLst = (from e in App.lstAllChilds where e.Id == Id select e).ToList();

列表在哪里lstAllChilds,其中还包含一些损坏的数据。

所以现在我想在这个查询中处理 Try-Catch 块。
请帮忙。

4

4 回答 4

11

如果您只想忽略“坏元素”,那么:

App.lstAllChilds.SkipExceptions().Where( e => e.Id == Id).ToList();

扩展方法:

 public static class Extensions
    {
        public static IEnumerable<T> SkipExceptions<T>(this IEnumerable<T> values)
        {
            using (var enumerator = values.GetEnumerator())
            {
                bool next = true;
                while (next)
                {
                    try
                    {
                        next = enumerator.MoveNext();
                    }
                    catch
                    {
                        continue;
                    }

                    if (next) yield return enumerator.Current;
                }
            }
        }
    }
于 2013-10-19T06:26:15.083 回答
4

Here is the simplest change you can make to simply exclude items which are null or are raising an exception.

tmpLst = App.lstAllChilds.Where(e =>
{
    try
    {
        return e != null && e.Id == Id;
    }
    catch
    {
        return false;
    }
}).ToList();

But in my opinion you probably should investigate and solve the underlying problem. This doesn't seem like a scenario where exceptions should be expected.

于 2013-10-19T06:29:29.550 回答
3

所以,事情就是这样。有语言集成查询(Linq),然后有产生的枚举(又名迭代器)。

Linq 允许您定义一个表达式树,该树稍后由可能是也可能不是 C# 的东西执行(例如,表达式可以被翻译成 SQL 查询)。如果您正在编写 linq,则很有可能您的查询提供程序(执行表达式转换的东西)不支持异常处理(更不用说您正在做的任何事情都会引发异常)。

另一方面,Interators(或“linq to objects”)最终会在 C# 中执行,因此您可以疯狂地处理异常。

例如 w/ linq to objects 你可以这样做:

var myList = new[] { "1", "2", "BARF", "3" };
var sum = myList.Select(str => {
  try {
    return Int32.Parse(str);
  } catch {
    return 0;
  }
}).Aggregate((x, y) => x + y);

如果您确实在对对象进行 linq,并且您只想跳过源 IEnumerable 引发异常的元素,请查看 Vladimir Gondarev 的回答。

然而,需要理解的重要一点是,我们刚刚传递给 Select 调用的匿名函数不是 Expression(未编译的表达式树),而是 Func(指向已编译 c# 代码的委托),这意味着它将运行在 .Net 进程中,即使我们将 myList 替换为 linq to entity 表(或其他一些 linq 提供程序)。原因是 C# 表达式语法不支持块,也不支持 try-catch。不出所料,SQL 风格的 Linq 语句(来自 xxx select yyy)也不支持 try-catch 块。

但是,仅仅因为 C# 表达式语法不支持它并不意味着您不能这样做。但是,需要明确的是,我不建议这样做,因为我非常怀疑是否存在支持它的 QueryProvider(除了 linq to objects 提供程序)。对于好奇的人,这里是如何创建一个包含 try-catch 块的 lambda 表达式。

var parseMethod = typeof(Int32).GetMethod("Parse", new[] { typeof(String) });
var param = Expression.Parameter(typeof(String));
var selectExp =
    Expression.Lambda<Func<String, Int32>>(
        Expression.TryCatch(
            Expression.Call(parseMethod, param),
            Expression.Catch(typeof(Exception), Expression.Constant(0))
        ),
        param
    );
var sum = myList.Select(selectExp).Aggregate((x, y) => x + y);

因此,当有人实现由支持异常处理的商店支持的 QueryProvider 时,您可以使用它。

于 2013-10-19T06:57:03.977 回答
2

这取决于您到底要达到什么目标:

  1. 返回除“损坏”项目之外的列表。

    • 您可以尝试使用Where子句来检查和过滤它们:

      App.lstAllChilds.Where(x => IsValidNode(x, Id)).ToList();
      

      显然你需要实现IsValidNodewhich 应该检查null,如果它可以抛出一个InvalidObjectException(不确定你是否可以轻松检测到它,但你总是可以将它包装在一个 try-catch 块中)和Id相等性。像那样:

      private bool IsValidNode(Child c, int id)
      {
          if (x == null) return false;
          try {
              return c.Id == id;
          }
          catch (InvalidObjectException)
          {
      
          }
          return false;
      }
      
  2. 如果有任何损坏的项目,则返回一个空列表。

    • 只需将整个东西包装在一个 try-catch 块中
于 2013-10-19T06:24:46.740 回答