为什么这段代码是有效的C#代码?

时间:2012-11-15 15:55:41

标签: c# .net string null concatenation

  

可能重复:
  C#: Why is adding null to a string legal?

以下是有效的C#代码:

var samsung= "xyz" + null + null + null + null + "890";  // xyz890

这是无效的C#代码:

var iphone= null.ToString(); // compiler error

为什么以及如何使第一个语句有效,第二个语句无效?

9 个答案:

答案 0 :(得分:4)

+运算符用于连接字符串,因为null是字符串类的实例,所以它可以用作运算符的参数。 "xyz" + null最终返回字符串“xyz”,因此只需重复此过程,直到您实际添加"890"

虽然null可以用作方法参数的字符串对象,但实际上不能在其上调用方法,因为没有什么可以处理方法调用。

将方法视为对象处理外部请求的一种方式,事情更有意义。您可以向null的对象发送请求作为处理内容的参数,但实际上您无法要求null处理某些内容。

答案 1 :(得分:1)

C#编译器将连接中的null视为空字符串。

 var samsung= "xyz" + null + null + null + null + "890";

等于

 var samsung= "xyz" + ""+ ""+ ""+ ""+ "890";

当你试图调用null.toString()时,你实际上是在尝试在空对象上调用一个方法,如果它被编译,它总是会导致NullReferenceException

答案 2 :(得分:1)

使用第一行,您正在整理字符串。 null没什么,所以基本上你得到xyz890。这就像在做1+0+0+0+4但是对于你的第二个,你在ToString()上打电话给nullnull没什么,所以没有任何东西可以调用ToString()。您试图在非初始化变量上调用方法。

答案 3 :(得分:1)

由于string是引用类型,因此null可以隐式转换为string。在第一种情况下,+运算符的序列只会转换为String.Concat(obj1, obj2, obj3, ...)

要编译代码,可以调用Convert.ToString

var iphone = Convert.ToString(null);

答案 4 :(得分:1)

您可以将+运算符视为全局静态函数,如下所示:

+(string leftHandSide, string rightHandSide) {
  if (leftHandSide == null)
     leftHandSide = string.Empty;
  if (rightHandSide == null)
     rightHandSide = string.Empty;
  string returnValue;

  // concatenate string

  return returnValue;
}

由于此字符串连接方法是静态的,因此它不需要实例来调用它,它处理空值。但是,当您尝试在ToString上调用null时,没有对象的实例,因此没有ToString方法可以调用,因此异常。

答案 5 :(得分:1)

这是设计的。你可以阅读C# Language Specification。引用:

  

字符串连接:

string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);
     

二进制+运算符的这些重载执行字符串连接。   如果字符串连接的操作数是null,则为空字符串   取代。否则,任何非字符串参数都将转换为其   通过调用虚拟ToString方法表示字符串   继承自类型object。如果ToString返回null,则为空字符串   被替代。

     

[...]

所以,正如其他人所说,将+视为一种接受两个参数的方法,并且其中一个或两个都是null就可以了。

答案 6 :(得分:0)

因为在任何情况下都无法在null引用上调用方法,所以编译器不允许它。在第一种情况下,编译器将预编译字符串常量为"xyz890",因此它是一个合法的赋值。

通常,+的{​​{1}}运算符会编译为支持string个参数的String.Concat(s1, s2, ...)

为了更精确地说明第二种情况,实际问题并不是它是一个空指针,而是没有 type 来绑定方法。正如其他评论中所指出的,您可以将null转换为任何引用类型,并且编译得很好:

null

答案 7 :(得分:0)

+运算符将转换为静态函数,看起来很像:

public static string Concat(string first, string second) {...}

将null作为参数传递给函数不是问题;它传递得很好。该函数恰好在连接它们之前检查这两个参数都不为null;如果任何参数为null,则将它们视为空字符串,以免引起异常。这里的关键点是,在这个函数首次对null进行空检查之前,不会调用字符串的实例成员。

至于null.ToString()在编译时评估为null的任何事物上调用实例函数会导致异常。这是该案件的定义。

答案 8 :(得分:0)

如果你看一下IL,你会发现编译器足够智能,只需删除空值并创建一个连接字符串。如前所述,你不能做null.ToString();你可以执行string.Empty或将字符串赋值为null。

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       8 (0x8)
  .maxstack  1
  .locals init ([0] string samsung)
  IL_0000:  nop
  IL_0001:  ldstr      "xyz890"        //null has been removed by compiler.  
  IL_0006:  stloc.0
  IL_0007:  ret
} // end of method Program::Main 

修改
展开Nielson的评论。由于null表示nil引用,因此可以公平地说,处理字符串concat的方式是C#许可,例如操作。我想知道它使用字节数组构建,它会省略空值,因此只是让它看起来好像是在为null。