为什么添加两个空字符串的结果不为null?

spe*_*tzz 42 c# string null

当我在.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 ");
        }
    }
Run Code Online (Sandbox Code Playgroud)

我得到了输出No meow,这意味着字符串不是null.这怎么可能?为什么添加两个null字符串会导致非null字符串?

在调试时,我检查xyz将其添加到自身后的值,其值为""(无字符).

dca*_*tro 67

来自MSDN:

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

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

xyz = String.+(null, null);
Run Code Online (Sandbox Code Playgroud)

然后,实现将解释为好像它

xyz = String.+("", "");
Run Code Online (Sandbox Code Playgroud)

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

x op = y形式的操作通过应用二元运算符重载决策(第7.3.4节)来处理,就好像操作是用x op y编写的一样.

  • 值得注意的是,运算符是静态的,而不是实例的方法. (7认同)
  • @DanielA.White按建议添加了备注. (2认同)

Alb*_*rto 24

当您使用+=运算符时,您实际上正在调用string.Concat方法,如文档中所述:

该方法连接str0和str1; 它不会添加任何分隔符. 使用Empty字符串代替任何null参数.

实际上这段代码:

string xyz = null;
xyz += xyz;
Run Code Online (Sandbox Code Playgroud)

将汇编成:

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
Run Code Online (Sandbox Code Playgroud)

  • 挑剔点:实际上,编译器会在极少数情况下忽略对String.Concat`的调用. (4认同)

Jon*_*nna 6

如上所述,原因是连接null被认为与连接空字符串相同.

值得考虑为什么这种行为很有用.

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

  1. 结果为null.
  2. 该操作是一个无操作,我们留下了另一个操作数.

这是有道理的,例如,该((int?)null) + 3结果null,一般要么这将是最有用的结果,还是一个我们会自觉防范(也就是,我们将添加代码来显式地捕获空的情况下).

但是有两个原因不能用字符串连接来做到这一点.

首先要考虑的是,由于连接意味着不是算术计算,而是将两个东西粘在一起,那么将null固定在某事物的开头或结尾上的最合理的结果是什么?很容易说这不应该做什么,而不是返回null.

第二个是在实践中,我们希望a + b + c + d字符串返回null(如果其中任何一个为null)的情况会比我们不希望的情况更少.

从中可以看出,在连接中将null视为空字符串是有意义的.从这个基础来看,(string)null + (string)null结果""是因为我们没有连接过零的特殊情况.

可以添加这种特殊情况,但随后可以添加x + "" == x + null不再存在的属性,这可能会导致一些奇怪的情况.