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

时间:2014-02-14 11:39:45

标签: 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 ");
        }
    }

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

在我将xyz添加到自身后检查""的值时进行调试时,其值为{{1}}(无字符)。

6 个答案:

答案 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时,我们可以使用二元运算符做两件明智的事情:

  1. 结果为空。
  2. 操作是无操作,我们留下了另一个操作数。
  3. 例如,((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