可能的重复项:
C#:为什么在字符串中添加 null 是合法的?
下面是有效的 C# 代码:
var samsung= "xyz" + null + null + null + null + "890"; // xyz890
这是无效的 C# 代码:
var iphone= null.ToString(); // compiler error
为什么以及如何第一个语句有效而第二个语句无效?
+
运算符用于连接字符串,由于null
是字符串类的实例,因此可以用作运算符的参数。 "xyz" + null
最终返回字符串"xyz",因此只是重复此过程,直到您实际添加"890"
。
虽然 null 可以用作方法参数的字符串对象,但实际上不能对其调用方法,因为没有内容可以处理方法调用。
将方法视为对象处理外部请求的一种方式,事情更有意义。您可以使用null
向对象发送请求作为要处理的内容的参数,但实际上不能要求null
处理某些内容。
使用第一行,您正在连接字符串。 null
什么都不是,所以基本上你得到了xyz890
. 这就像做1+0+0+0+4
但是对于你的第二个,你被称为ToString()
null
. null
什么都不是,所以没有什么可以叫ToString()
的。 您正在尝试对未初始化的变量调用方法。
由于 string
是引用类型,因此 null 可以隐式转换为 string
。在第一种情况下,+
运算符序列只是转换为String.Concat(obj1, obj2, obj3, ...)
要使代码编译,您可以调用Convert.ToString
:
var iphone = Convert.ToString(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
mehthod,因此异常。
C# 编译器将串联中的 null 视为空字符串。
var samsung= "xyz" + null + null + null + null + "890";
等于
var samsung= "xyz" + ""+ ""+ ""+ ""+ "890";
当您尝试调用null.toString()
时,您实际上是在尝试在 null 对象上调用方法,该方法(如果编译)总是会导致NullReferenceException
。
这是设计使然。您可以阅读 C# 语言规范。报价:
字符串连接:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
二进制
+
运算符的这些重载执行字符串串联。 如果null
字符串连接的操作数,则空字符串为 取代。否则,任何非字符串参数都将转换为其 通过调用虚拟ToString
方法表示字符串 继承自object
型 。如果ToString
返回null
,则为空字符串 被替换。[...]
因此,正如其他人所说,将+
视为一种接受两个参数的方法,并且可以null
其中一个或两个参数。
+ 运算符将被转换为一个静态函数,如下所示:
public static string Concat(string first, string second) {...}
将 null 作为参数传递给函数不是问题;它传递得很好。 该函数碰巧在连接它们之前检查两个参数都不是 null;如果任何参数为 null,则将它们视为空字符串,以免导致异常。 这里的关键点是,在此函数首次检查字符串 null 之前,不会调用字符串的实例成员。
至于null.ToString()
在编译时计算结果为 null
的任何内容上调用实例函数会导致异常。 这就是该案的定义。
因为在任何情况下都不能在 在第一种情况下,编译器会将字符串常量预编译为null
引用上调用方法,所以编译器不允许这样做。"xyz890"
因此它是合法赋值。
通常,string
的+
运算符编译为支持null
参数的String.Concat(s1, s2, ...)
。
更准确地说,第二种情况,实际问题不在于它是一个空指针,而在于没有将方法绑定到的类型。 正如其他注释中指出的,您可以将null
转换为任何引用类型,并且可以很好地编译:
((string)null).ToString(); // compiles, but fails at run-time.
如果您查看 IL,您会发现编译器足够聪明,只需删除 null 值并创建一个串联字符串。 如前所述,您不能执行空值。ToString();你可以做字符串。为空或将字符串分配为 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# 允许,例如操作。 我会理解它使用字节数组构建,它会省略空值,从而简单地让它看起来像是连接空值。