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

C# 为什么这个代码是有效的C代码?,c#,.net,string,null,concatenation,C#,.net,String,Null,Concatenation,可能重复: 以下是有效的C#代码: 这是无效的C代码: 为什么第一条语句有效,第二条语句无效?因为在任何情况下都不能对null引用调用方法,所以编译器不允许它。在第一种情况下,编译器会将字符串常量预编译为“xyz890”,因此它是合法的赋值 通常,string的+运算符编译为string.Concat(s1,s2,…),它支持null参数 更确切地说,在第二种情况下,实际的问题不是它是一个空指针,而是没有可以绑定该方法的类型。正如在其他注释中指出的,您可以将null强制转换为任何引用类型,它编

可能重复:

以下是有效的C#代码:

这是无效的C代码:

为什么第一条语句有效,第二条语句无效?因为在任何情况下都不能对
null
引用调用方法,所以编译器不允许它。在第一种情况下,编译器会将字符串常量预编译为
“xyz890”
,因此它是合法的赋值

通常,
string
+
运算符编译为
string.Concat(s1,s2,…)
,它支持
null
参数

更确切地说,在第二种情况下,实际的问题不是它是一个空指针,而是没有可以绑定该方法的类型。正如在其他注释中指出的,您可以将
null
强制转换为任何引用类型,它编译得很好:

((string)null).ToString();   // compiles, but fails at run-time.
C#编译器将串联中的null视为空字符串

 var samsung= "xyz" + null + null + null + null + "890";
相等于

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

当您尝试调用
null.toString()
时,实际上是在尝试调用null对象上的方法,这(如果已编译)将始终导致
NullReferenceException

在第一行中,您将包含字符串
null
什么都不是,所以本质上您得到的是
xyz890
。这就像执行
1+0+0+0+4
,但使用第二个,您将在
null
上调用
ToString()
null
是nothing,因此没有可调用的
ToString()。您正试图对未初始化的变量调用方法。

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

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

var iphone = Convert.ToString(null);

+运算符将转换为一个静态函数,该函数类似于:

public static string Concat(string first, string second) {...}
将null作为参数传递给函数不是问题;它通过得很好。该函数在合并参数之前检查两个参数是否为null;如果任何参数为null,则将其视为空字符串,以免导致异常。这里的关键点是,在该函数首次检查字符串的实例成员为null之前,不会调用它们


至于
null.ToString()
在编译时对任何计算结果为
null
的对象调用实例函数都会导致异常。这正是这种情况的定义。

如果您查看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 
编辑

扩大尼尔森的评论。由于null表示一个nil引用,因此可以公平地说,字符串concat的处理方式是C#允许的,比如操作。我想知道它使用字节数组构建,这会忽略空值,从而使它看起来像是包含空值

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

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


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

您可以将
+
操作符看作一个全局静态函数,如下所示:

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

  // concatenate string

  return returnValue;
}

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

这是出于设计。你可以看报纸。引述:

字符串连接:

string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);
二进制
+
运算符的这些重载执行字符串连接。 如果字符串串联的操作数为
null
,则为空字符串 替换。否则,任何非字符串参数都将转换为其 通过调用virtual
ToString
方法来表示字符串 继承自类型
对象
。如果
ToString
返回
null
,则为空字符串 被替换

[……]


因此,正如其他人所说,将
+
视为一种方法,它接受两个参数,如果其中一个或两个参数都为
null

则可以。您不能更改
任何内容(此处为null),是否想知道编译器是否删除了null添加项?有人知道吗?@格兰斯。如果它们是空常量,则为是。事实上,整个表达式在IL中简化为
“xyz890”
。@GrantH。是的,但从技术上讲,这不会改变结果,只会改变性能。如果它在编译时没有将其求值为单个常量(您可以简单地更改它以阻止它这样做),那么它仍然可以工作,如果它不能在运行时运行它,那么它将无法在编译时对其进行优化。换言之,编译时优化并没有改变为什么它会起作用或不起作用的解释!非常感谢大家:-)我的问题得到了回答。@user1688826如果你的问题得到了回答,你应该接受回答。虽然这没有错,但你并没有解释为什么你可以这样做
+(string leftHandSide, string rightHandSide) {
  if (leftHandSide == null)
     leftHandSide = string.Empty;
  if (rightHandSide == null)
     rightHandSide = string.Empty;
  string returnValue;

  // concatenate string

  return returnValue;
}
string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);