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



当我在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的值添加到它自己之后检查它的值时,它的值是""(没有字符)。

来自MSDN:

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

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

xyz = String.+(null, null);

然后,实现将把它解释为

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

(*)C#规范第7.17.2节:

形式为x op=y的操作通过应用二进制运算符重载解析(§7.3.4)进行处理,就好像该操作是写xopy

使用+=运算符时,实际上是在调用字符串。Concat方法,如文档中所述:

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

事实上,这个代码:

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与连接空字符串相同。

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

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

  1. 结果为null
  2. 该操作是一个非操作数,剩下另一个操作数

例如,((int?)null) + 3导致null是有道理的,通常这要么是最有用的结果,要么是我们有意识地防范的结果(也就是说,我们将添加代码来明确捕获null大小写)。

但是,有两个原因不使用字符串串联。

首先要考虑的是,既然串联不是算术计算,而是将两件事粘在一起,那么在某件事的开头或结尾加零最合理的结果是什么?很容易证明这应该什么都不做,而不是返回null。

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

因此,将null视为串联中的空字符串是有意义的。在此基础上,(string)null + (string)null导致""是因为我们没有连接过多null的特殊情况。

可以添加该特殊情况,但x + "" == x + null的属性将不再具有,这可能会导致一些奇怪的情况。

这是因为运算符+=将Null添加到Empty字符串。

因此,编译器会向现有字符串对象添加空字符串。

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

试试这个。。。

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

C#从Java借用了其+运算符的行为。如果+的任何一个操作数是字符串,+运算符将调用String.Concat,后者接受类型Object,并在传递给它的每个非null对象上连接调用ToString的结果。忽略null引用只是String.Concat的操作数本身不被视为"字符串"的一小部分;这种行为的一个更值得注意的方面是,非字符串类型的ToString方法被调用,无论它们是否可以隐式转换为string

相关内容

  • 没有找到相关文章