所以,事情就是这样。有语言集成查询 (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 语句(from 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 时,您可以使用它。