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
,则为空字符串
替换。否则,任何非字符串参数都将转换为其
通过调用virtualToString
方法来表示字符串
继承自类型对象
。如果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);