【发布时间】:2014-03-31 07:08:19
【问题描述】:
我的同事告诉我以下代码不正确,如果我的变量为 null,则会崩溃:
List<FSKUser> users = null;
if (users == null || users.Count() == 0)
{
return false;
}
显然=null 仅用于测试目的。但是当我运行这段代码时,它运行正确并返回 false。
我检查的方式是安全正确的检查方式吗?
【问题讨论】:
我的同事告诉我以下代码不正确,如果我的变量为 null,则会崩溃:
List<FSKUser> users = null;
if (users == null || users.Count() == 0)
{
return false;
}
显然=null 仅用于测试目的。但是当我运行这段代码时,它运行正确并返回 false。
我检查的方式是安全正确的检查方式吗?
【问题讨论】:
是的,这是安全正确的方法。您的同事可能对 C# 中的运算符优先级或布尔表达式求值有一些奇怪的理解:)
|| 运算符(与&& 相同)将在确定结果后立即停止评估。因为一旦操作数之一是 true,布尔 OR 永远不会产生 false,所以它会在第一个操作数上失败(如果它为 null,则结果是 true => 你'完成),否则它将评估两个运算符。
当然,如果您不反对使用扩展方法,这可以方便地用于简化条件。例如。你可以使用这样的扩展方法:
public static bool IsEmpty<T>(List<T> @this)
{
return @this == null || @this.Count == 0;
}
然后你可以使用这样的条件:
if (users.IsEmpty())
{
...
}
另外,请注意List<T> 有一个Count 属性——您可能应该使用它而不是扩展方法Count()。最后,它会做同样的事情 IIRC(它检查枚举是一个集合还是一个列表,IIRC),但它会通过一些循环来做到这一点。
您可能想问问您的同事他认为会发生什么。你有一个简单的测试用例表明你是对的,但也许他有他自己的一些原因,为什么他不想要那个。然而,最有可能的是他习惯了另一种编程语言,而不是真正的原生 C#-er。在这种情况下,你们俩都有机会学习:)
【讨论】:
.Count 属性(无括号)。使用List<> 速度很快。 Linq 扩展会发现这是一个ICollection<> 并使用Count 属性。但是,如果您想要 Linq,请改用 .Any(),因为它更短、更精确,并且在底层源不是List<> 时可以更快。
你的朋友错了。 || 运算符 short-circuits - 当任何术语第一次返回 true 时,它会以 true 退出。同样,&& 运算符在任何术语第一次返回false 时以false 退出。因此,如果users 是null,则您的users.Count() 无法 到达(除非users 是一个字段并且您正在执行大量线程,并且编译器和JIT出于某种原因选择显式加载该字段两次)。
【讨论】:
您的代码没有问题。仅当用户不等于 null 时才会评估第二个条件,因此这是检查 null 的正确方法。
与其他语言相比(VB.NET 和And 和Or 运算符,而不是AndAlso 和OrElse),C# 只评估条件,只要它们的结果对整体结果有影响.如果 - 就像你的情况一样 - 逻辑或运算的第一个条件已经评估为真,则无需检查第二个条件。
【讨论】:
这可能对您的示例有用:
List<FSKUser> users = null;
return users != null && users.Any();
【讨论】: