gdo*_*ica 6 .net c# linq linq-to-entities linq-to-sql
我有这个Linq对象查询:
var result = Users.Where(u => u.Address.Country.Code == 12)
Run Code Online (Sandbox Code Playgroud)
如果Address或Country为null,我会收到异常.
为什么这个查询不会检查地址是否为空并且只是在该地址之后?这样我就不需要写这个可怕的查询了:
var result = Users.Where(u => u.Address != null &&
u.Address.Country != null &&
u.Address.Country.Code == 12)
Run Code Online (Sandbox Code Playgroud)
在Linq to SQL中,第一个查询将完成工作(当然是出于其他原因).
是一种避免linq中的"空检查"对象的方法吗?
不幸的是,在C#(以及许多其他编程语言)中,"null"被不一致地处理.可空算术被解除了.也就是说,如果你对可空整数进行算术运算,并且没有操作数为空,那么你得到正常的答案,但是如果它们中的任何一个为空,你就得到null.但是"成员访问"操作员没有解除; 如果你给成员访问"."一个空操作数.运算符,它抛出异常而不是返回空值.
如果我们从头开始设计类型系统,我们可能会说所有类型都是可空的,并且包含空操作数的任何表达式都会产生null结果,而不管操作数的类型如何.因此,使用null接收器或null参数调用方法将产生null结果.这个系统很有意义,但显然我们现在实施它已经太晚了; 已经编写了数百万行代码来预期当前的行为.
我们已经考虑过添加一个"提升"的成员访问操作符,可能是标记的.?.所以你可以说where user.?Address.?Country.?Code == 12,那会产生一个可以为空的int,然后可以将它作为可空的int通常比较为12.然而,这一点从来没有超过"是的,在未来的版本中可能很好"的设计过程阶段,所以我不希望它很快.
更新:上面提到的"Elvis"运算符是在C#6.0中实现的.
不,这是一个空引用异常就像访问var x = u.Address.Country.Code;将是一个NullReferenceException.
您必须始终确保您要取消引用的内容不在nullLINQ to对象中,就像使用任何其他代码语句一样.
您可以使用&&您拥有的逻辑执行此操作,也可以链接Where子句(尽管这将包含更多迭代器并且执行速度可能更慢):
var result = Users.Where(u => u.Address != null)
.Where(u.Address.Country != null)
.Where(u.Address.Country.Code == 12);
Run Code Online (Sandbox Code Playgroud)
注意:Maybe()下面的方法只是作为"你也可以"的方法提供,我不是说它的好坏,只是展示一些人做的事情.如果你不喜欢Maybe()我只是重复我见过的各种解决方案,请不要投票.
我已经看到了一些Maybe()编写的扩展方法,可以让你做你想做的事情.有些人不喜欢这些,因为它们是对null引用进行操作的扩展方法.我不是说这是好还是坏,只是有些人觉得违反了良好的OO行为.
例如,您可以创建一个扩展方法,如:
public static class ObjectExtensions
{
// returns default if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator)
where TInput : class
{
return (value != null) ? evaluator(value) : default(TResult);
}
// returns specified value if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
return (value != null) ? evaluator(value) : failureValue;
}
}
Run Code Online (Sandbox Code Playgroud)
然后做:
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code) == 12);
Run Code Online (Sandbox Code Playgroud)
从本质上讲,这只是null将链条向下级联(或者在非引用类型的情况下为默认值).
更新:
如果您想提供非默认的失败值(如果任何部分为空,则代码为-1),您只需将新的失败值传递给Maybe():
// if you wanted to compare to zero, for example, but didn't want null
// to translate to zero, change the default in the final maybe to -1
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code, -1) == 0);
Run Code Online (Sandbox Code Playgroud)
就像我说的,这只是众多解决方案中的一种.有些人不喜欢能够从null引用类型调用扩展方法,但是有些人倾向于使用它来解决这些null级联问题.
但是,目前C#中没有内置的null-de-reference运算符,所以要么像以前一样使用条件空值检查,要么链接你的Where()语句以便它们过滤掉null,或者构建一些东西让你null像Maybe()上面的方法一样级联.
| 归档时间: |
|
| 查看次数: |
3206 次 |
| 最近记录: |