Dav*_*ave 23 c# linq exception-handling .net-3.5
...我有点困惑,或者不确定如何处理LINQ语句中出现的错误.我只是喜欢能够拉动一个或多个项目的集合,基于某些条件......一个单一的代码行.那真是太棒了.
But where I'm torn is with the error handling, or the boundary condition checking. If I want to retrieve an item using First(), and no item satisfies my query, an exception gets thrown. That's a bit of a bummer because now I have to wrap every LINQ statement with a separate try/catch block. To me, the code starts to look a little messy with all of this, especially since I end up having to declare variables outside of the try/catch block so I can use their (null) values later (which were set to null in the catch block).
Does anyone here understand my predicament? If I have to wrap every LINQ statement in try/catch blocks, I will, because it's still a hell of a lot better than writing all sorts of for loops to accomplish the same thing. But there must be a better way, right? :) I'd like to hear what everyone else here does in this situation.
**UPDATE**
Thanks for the answers, guys, they have been very helpful. One other thing I also was going to bring up, along the "one-lineness" of LINQ, is that if I want to get some .some_value.some_value.some_other_value, if I adopt an approach where I have to check for a Nullable, I have to do it from the most basic LINQ query first, then I can query for the result's property that I'm looking for. I guess there's no way around this?
Eri*_*ert 55
当您知道集合中有一个或多个项目时,请使用First .当您知道集合中只有一个项目时,请使用Single .如果您不了解这些事情,请不要使用这些方法.使用其他方法,如FirstOrDefault(),SingleOrDefault()等.
例如,您可以说:
int? first = sequence.Any() ? (int?) sequence.First() : (int?) null;
Run Code Online (Sandbox Code Playgroud)
这远远不如
int? first = null;
try { first = sequence.First(); } catch { }
Run Code Online (Sandbox Code Playgroud)
但仍然不是很好,因为它迭代序列的第一项两次.在这种情况下,我会说如果没有序列运算符可以执行您想要的操作,那么请编写自己的序列运算符.
继续我们的示例,假设您有一个整数序列并想要获取第一个项目,或者,如果没有一个,则返回null.没有内置的序列运算符可以做到这一点,但是编写它很容易:
public static int? FirstOrNull(this IEnumerable<int> sequence)
{
foreach(int item in sequence)
return item;
return null;
}
Run Code Online (Sandbox Code Playgroud)
甚至更好:
public static T? FirstOrNull<T>(this IEnumerable<T> sequence) where T : struct
{
foreach(T item in sequence)
return item;
return null;
}
Run Code Online (Sandbox Code Playgroud)
或这个:
struct Maybe<T>
{
public T Item { get; private set; }
public bool Valid { get; private set; }
public Maybe(T item) : this()
{ this.Item = item; this.Valid = true; }
}
public static Maybe<T> MyFirst<T>(this IEnumerable<T> sequence)
{
foreach(T item in sequence)
return new Maybe(item);
return default(Maybe<T>);
}
...
var first = sequence.MyFirst();
if (first.Valid) Console.WriteLine(first.Item);
Run Code Online (Sandbox Code Playgroud)
但无论你做什么,都不要处理你提到的那些例外.这些异常并不意味着要处理,它们是为了告诉您代码中存在错误.你不应该处理它们,你应该修复bug.在他们周围放置试图隐藏错误,而不是修复错误.
更新:
Dave询问如何创建一个带谓词的FirstOrNull.很容易.你可以这样做:
public static T? FirstOrNull<T>(this IEnumerable<T> sequence, Func<T, bool> predicate) where T : struct
{
foreach(T item in sequence)
if (predicate(item)) return item;
return null;
}
Run Code Online (Sandbox Code Playgroud)
或者像这样
public static T? FirstOrNull<T>(this IEnumerable<T> sequence, Func<T, bool> predicate) where T : struct
{
foreach(T item in sequence.Where(predicate))
return item;
return null;
}
Run Code Online (Sandbox Code Playgroud)
或者,甚至不要打扰:
var first = sequence.Where(x=>whatever).FirstOrNull();
Run Code Online (Sandbox Code Playgroud)
没有理由为什么谓词必须继续使用FirstOrNull.我们提供了一个First(),它将谓词作为一个方便,这样你就不必输入额外的"Where".
更新:Dave问另一个后续问题,我认为可能是"如果我想说sequence.FirstOrNull().Frob().Blah().无论什么()但沿线的任何一个都可以返回null? "
我们已经考虑过向C#添加一个null传播的成员访问运算符,暂时标注为?.- 也就是说,你可以说
x = a?.b?.c?.d;
如果a,b或c产生null,那么结果将是为x赋值null.
显然我们实际上没有为C#4.0实现它.对于假设的语言未来版本,这是一个可能的工作项... 更新"猫王操作员"已被添加到C#6.0,是的!
请注意,C#确实有一个空的合并运算符:
(sequence.FirstOrNull()?? GetDefault()).Frob().Blah().Whatever()
表示"如果FirstOrNull返回非null,则将其用作Frob的接收者,否则调用GetDefault并将其用作接收者".另一种方法是再次编写自己的方法:
public static T FirstOrLazy<T>(this IEnumerable<T> sequence, Func<T> lazy)
{
foreach(T item in sequence)
return item;
return lazy();
}
sequence.FirstOrLazy(()=>GetDefault()).Frob().Blah().Whatever();
Run Code Online (Sandbox Code Playgroud)
现在你得到第一个项目,如果有的话,或者调用GetDefault()的结果(如果没有).
Red*_*ter 22
Use FirstOrDefault and then check for null.
| 归档时间: |
|
| 查看次数: |
7306 次 |
| 最近记录: |