对于我的编程考试,我必须为我编写的代码辩护。其中一条线是:
if(app.Logourl == "" || app.Logourl == null)
他问我null和空字符串之间是否有区别。我告诉他,区别在于null
表示它没有指向任何东西,所以它没有实例化,但是空字符串是。
考试结束后,我走到他身边,问他是否正确,因为我看到他脸上的滑稽表情。他告诉我,他们的确是不同的,但我检查数值的顺序是不正确的。
现在几天后,我相信订单没有错。我是对的吗?
TL; DR
是
if(app.Logourl == "" || app.Logourl == null)
相当于
if(app.Logourl == null || app.Logourl == "")
答案 0 :(得分:14)
你做的方式没问题,因为==
的{{1}}超载调用String.Equals
,允许System.String
s。
这不是通用的,但是:如果您想检查字符串长度而不是使用null
,那么您的第一个代码段将遇到麻烦:
== ""
而第二个没问题:
if(app.Logourl.Length == 0 || app.Logourl == null) // <<== Wrong!
原因是评估if(app.Logourl == null || app.Logourl.Length == 0) // <<== Correct
和||
运营商时出现短路:一旦他们知道结果(&&
true
,||
对于false
)他们停止评估。在上面的第二个代码段中,如果&&
为app.Logourl
,则表达式的后半部分将被忽略,因此null
不会抛出空引用异常。
注意:为了识别这样的支票在各处发生,C#类库offers a convenience method for doing this check:
app.Logourl.Length
答案 1 :(得分:2)
private static bool IsNullOrEmpty(string s)
{
return s == null || s == "";
/*
Lets look behind the scenes here:
=================================
IL_0000: ldarg.0 => load s on the evaluation stack
IL_0001: brfalse.s IL_000f => GoTo label 'IL_000f' if loaded argument is null
IL_0003: ldarg.0 => load s on the evaluation stack
IL_0004: ldstr "" => load constant string "" to the evaluation stack
IL_0009: call bool [mscorlib]System.String::op_Equality(string, string)
=> Call String.Equality(string,string) with s and ""
loaded to the evalutation stack
that will pop the two values compare them for equality and load the result.
to the evaluation stack.
IL_000e: ret => Return to the caller with equlity result on the evauation stack.
IL_000f: ldc.i4.1 => Load constant value 1(4 byte which will represent "True") to the evaluation stack
and return to the caller.In our flow it's the case when s is null.
IL_0010: ret
In Summary:
===========
1.) IL instructions total code size 17 bytes.
2.) Best case scenario execution path => 2 IL instructions.
3.) Worst case scenario execution pat => 8 IL instructions.
*/
}
private static bool IsEmptyOrNull(string s)
{
return s == "" || s == null;
/*
Lets look behind the scenes here:
=================================
IL_0000: ldarg.0 => load s on the evaluation stack
IL_0001: ldstr "" => load constant string "" to the evaluation stack
IL_0006: call bool [mscorlib]System.String::op_Equality(string, string)
IL_000b: brtrue.s IL_0012
IL_000d: ldarg.0 => load s on the evaluation stack
IL_000e: ldnull => load constant null on the evaluation stack
IL_000f: ceq => Pop two loaded values compare and push the result back on the evaluation stack
IL_0011: ret
IL_0012: ldc.i4.1 => Load constant value 1(4 byte which will represent "True") to the evaluation stack
and return to the caller.In our flow it's the case when s is null.
IL_0013: ret
In Summary:
===========
1.) IL instructions total code size 20 bytes.
2.) Best case scenario execution path => 6 IL instructions.
3.) Worst case scenario execution path => 10 IL instructions.
*/
}
仅通过IL发出的代码来判断 “if(app.Logourl ==”“|| app.Logourl == null)” 是“微观化”更好的表现明智:)
答案 2 :(得分:1)
不,没关系(在你的情况下)。
有一件事要知道,布尔运算符&&
和||
是短路的,这意味着如果你有a || b
而a
是true
,然后b
未被评估。
例如,
app.Logourl == null || app.Logourl == ""
如果app.Logourl
为null
,则app.Logourl == ""
甚至不会被评估。
在你的情况下,无论你检查一个还是另一个,都没有什么区别。第一个或第一个。如果检查有所不同,那就很重要。
例如,
app.Logourl == null || app.Logourl.Equals("")
如果您执行了其他订单,则app.Logourl
为null
时会出现异常,因为您无法调用空引用的成员函数。
虽然我使用String.IsNullOrEmpty(app.Logourl)
,这是标准的lib。
答案 3 :(得分:1)
这只是一个评论。
在通常情况下,这无关紧要。但是可能会有副作用。以下是一个值得学习的简单示例:
static class Program
{
static string Logourl
{
get
{
Console.WriteLine("getter runs");
return null;
}
}
static void Main()
{
if (Logourl == "" || Logourl == null)
{
}
}
}
该程序将写:
getter runs getter runs
如果您更换支票的顺序,getter runs
只会打印一次。如果您将属性更改为return "";
,则会相反。
当然,使用string.IsNullOrEmpry(Logurl)
将始终只检索一次属性。
答案 4 :(得分:0)
当我确定我的对象是string
时,我总是更喜欢以下内容:
if (string.IsNullOrEmpty(yourString))
{
// this string is null or empty
}
或者这个:
if (string.IsNullOrWhiteSpace(yourString))
{
// this string is null or empty (or got only a space)
}