为什么添加两个空string的结果不为空?

当我在.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 ,这意味着string不为null 。 这怎么可能? 为什么添加两个nullstring会导致非nullstring?

在debugging时,我检查xyz的值后添加到自己,它的值是"" (无字符)。

来自MSDN :

在string连接操作中,C#编译器将空string视为空string,

即使xyz为null,调用+ =运算符(将其转换为对其+运算符 (*)的调用)不会抛出NullReferenceException因为它是一个静态方法。 在伪代码中:

 xyz = String.+(null, null); 

然后这个实现将会像解释一样

 xyz = String.+("", ""); 

(*)C#规范的第7.17.2节:

x op = yforms的操作是通过应用二元运算符重载分辨率(§7.3.4)来处理的,就好像操作被写入x op y一样

当你使用+=运算符时,实际上是调用了string.Concat方法,就像文档中所述:

该方法连接str0和str1; 它不添加任何分隔符。 空string用于代替任何空参数。

其实这个代码:

 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 

如上所述,为什么连接null的原因与连接空string相同。

值得考虑为什么这种行为是有用的。

通常,当一个操作数为空时,我们可以用二元运算符做两件明智的事情:

  1. 结果是空的。
  2. 这个操作是没有操作的,我们剩下另一个操作数。

((int?)null) + 3结果为null是有意义的,一般来说这可能是最有用的结果,或者我们会自觉防范的(也就是说,我们将添加代码来捕获空的情况下明确)。

但是有两个原因不能用string连接来完成。

首先要考虑的是,由于连接意味着不是一个算术计算,而是把两件事情粘合在一起,那么什么是在事物的开始或结束时使用null的最合理的结果? 很容易使这个应该什么也不做,而不是返回null。

第二个是在实践中,我们希望带有stringa + b + c + d如果其中任何一个为空,就会返回null的情况比那些我们不会的情况less。

从这个angular度来看,将null作为串联中的空string是有意义的。 从这个基础上来说, (string)null + (string)null结果是"" ,因为我们没有特别的情况来连接太空。

可以添加特殊情况,但是x + "" == x + null将不再成立,这可能会导致一些奇怪的情况。

那是因为运算符+=将空值添加到空string。

因此,编译器将添加空string添加到现有的string对象。

所以它是空的而不是空的。

尝试这个…

 static void TestNullFunc(string abc) { if (string.IsNullOrEmpty( abc)) { Console.WriteLine("meow THERE ! "); } else { Console.WriteLine("No Meow "); } } 

C#借用Java的+运算符的行为。 如果两个操作数之一是一个string,那么+操作符将调用String.Concat ,它接受Objecttypes,并在传递给它的每个非null对象上连接调用ToString的结果。 空引用简单地被忽略的事实只是String.Concat操作数本身不被视为“string”的一小部分; 这种行为更为引人注目的一点是,不是string的types的ToString方法被调用,不pipe它们是否会被隐式地转换为string