以下是有效的C#代码:
var samsung= "xyz" + null + null + null + null + "890"; // xyz890
这是无效的C#代码:
var iphone= null.ToString(); // compiler error
为什么以及如何使第一个语句有效,第二个语句无效?
答案 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()
上打电话给null
。 null
没什么,所以没有任何东西可以调用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。