当我在.Net编程中遇到这种奇怪的行为时,我正在C#中摆弄。
我写了这段代码:
static void Main(string[] args)
{
string xyz = null;
xyz += xyz;
TestNullFunc(xyz);
Console.WriteLine(xyz);
Console.Read();
}
static void TestNullFunc(string abc)
{
if (abc == null)
{
Console.WriteLine("meow THERE ! ");
}
else
{
Console.WriteLine("No Meow ");
}
}
我的输出为No meow
,这意味着字符串不是null
。这怎么可能?为什么添加两个null
字符串会导致非null
字符串?
在我将xyz
添加到自身后检查""
的值时进行调试时,其值为{{1}}(无字符)。
答案 0 :(得分:67)
来自MSDN:
在字符串连接操作中,C#编译器将空字符串视为空字符串,
即使xyz
为null,调用+ =运算符(转换为对+ operator(*)的调用)也不会抛出NullReferenceException
,因为它是静态方法。在伪代码中:
xyz = String.+(null, null);
然后,实现会将其解释为
xyz = String.+("", "");
(*)C#规范的第7.17.2节:
通过应用二元运算符重载决策(第7.3.4节)处理 x op = y 形式的操作,就好像操作是写成 x op y 一样。
答案 1 :(得分:24)
当您使用+=
运算符时,您实际上正在调用string.Concat方法,如文档中所述:
该方法连接str0和str1;它不会添加任何分隔符。 使用空字符串代替任何空参数。
实际上这段代码:
string xyz = null;
xyz += xyz;
将编译成:
IL_0000: ldnull
IL_0001: stloc.0 // xyz
IL_0002: ldloc.0 // xyz
IL_0003: ldloc.0 // xyz
IL_0004: call System.String.Concat
IL_0009: stloc.0 // xyz
答案 2 :(得分:6)
如上所述,原因是连接null与连接空字符串相同。
值得考虑为什么这种行为很有用。
通常,当其中一个操作数为null时,我们可以使用二元运算符做两件明智的事情:
例如,((int?)null) + 3
会产生null
,这通常会是最有用的结果,或者我们会有意识地防范(也就是说,我们会添加代码)明确地捕捉空案例。)
但是有两个理由不使用字符串连接来执行此操作。
首先要考虑的是,由于连接意味着不是算术计算,而是将两个事物粘在一起,那么将null固定在某事物的开头或结尾上的最合理的结果是什么?很容易说这不应该做什么,而不是返回null。
第二个是在实践中,我们希望a + b + c + d
字符串返回null(如果其中任何一个为null)的情况将会少于我们不希望的情况。
从那时起,将null视为连接中的空字符串是有意义的。在此基础上,(string)null + (string)null
导致""
的结果是因为我们没有连接太多空的特殊情况。
可以添加特殊情况,但是x + "" == x + null
将不再存在的属性,这可能会导致一些奇怪的情况。
答案 3 :(得分:2)
这是因为运算符+=
将Null添加为空字符串。
因此,编译器会将空字符串添加到现有字符串对象。
所以它是空的而不是空的。
答案 4 :(得分:2)
试试这个......
static void TestNullFunc(string abc)
{
if (string.IsNullOrEmpty( abc))
{
Console.WriteLine("meow THERE ! ");
}
else
{
Console.WriteLine("No Meow ");
}
}
答案 5 :(得分:1)
C#借用了来自Java的+
运算符的行为。如果+
的任一操作数是一个字符串,+
运算符将调用String.Concat
,它接受类型Object
并连接每个非调用ToString
的结果-null传递给它的对象。简单地忽略空引用这一事实只是String.Concat
的操作数本身不被视为“字符串”的一小部分;这种行为的一个更明显的方面是,不是字符串的类型调用了它们的ToString
方法,无论它们是否可以隐式转换为string
。