为什么它是有效连接空string,但不要调用“null.ToString()”?

这是有效的C#代码

var bob = "abc" + null + null + null + "123"; // abc123 

这不是有效的C#代码

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

为什么第一个陈述是有效的?

第一个工作的原因是:

来自MSDN :

在string连接操作中,C#编译器将空string视为空string,但不转换原始空string的值。

有关+二元运算符的更多信息:

当一个或两个操作数是stringtypes时,二元+运算符执行string连接。

如果string连接的操作数为空,则replace空string。 否则,通过调用从objecttypesinheritance的虚拟ToString方法,将任何非string参数转换为其string表示forms。

如果ToString返回null ,则replace空string。

第二个错误的原因是:

null(C#参考) – null关键字是表示空引用的文字,不引用任何对象。 null是引用typesvariables的默认值。

因为C#中的+运算符在内部转换为String.Concat ,这是一个静态方法。 而这个方法恰好把null当作一个空string来处理。 如果你看看Reflector中的String.Concat的来源,你会看到它:

 // while looping through the parameters strArray[i] = (str == null) ? Empty : str; // then concatenate that string array 

(MSDN也提到它: http : //msdn.microsoft.com/en-us/library/k9c94ey1.aspx )

另一方面, ToString()是一个实例方法,你不能在null调用(什么types应该用于null ?)。

一个样本将被翻译成:

 var bob = String.Concat("abc123", null, null, null, "abs123"); 

Concat方法检查input并将空string转换为空string

第二个样本将被翻译成:

 var wtf = ((object)null).ToString(); 

所以在这里会产生一个null引用exception

你的代码的第一部分就像在String.Concat中那样String.Concat

这是C#编译器在添加string时调用的内容。 “ abc" + null被转换为String.Concat("abc", null)

在内部,该方法用String.Emptyreplacenull 。 所以,这就是为什么你的第一部分代码不会抛出任何exception。 它就像

 var bob = "abc" + string.Empty + string.Empty + string.Empty + "123"; //abc123 

在代码的第二部分抛出exception,因为'null'不是一个对象, null关键字是一个表示空引用的文字,不引用任何对象。 null是引用typesvariables的默认值。

而' ToString() '是一个方法,可以被一个对象的实例调用,但不是任何文字。

在.net之前的COM框架中,任何接收到string的例程在完成时都需要释放它。 由于空string被传入和传出例程是非常常见的,而且由于试图将空指针“释放”被定义为合法的无作用操作,Microsoft决定让空string指针表示一个空string。

为了与COM有一定的兼容性,.net中的许多例程将把空对象解释为空string的合法表示。 对于.net及其语言(最明显的是允许实例成员表示“不要调用为虚拟”),微软可能已经使得声明的types为String的null对象更像空string。 如果微软已经这么做了,那么它也必须使Nullable<T>工作有些不同(以便允许Nullable<String> – 它们应该是IMHO所做的事情)和/或定义一个NullableStringtypes,与String可互换,但不会将null视为有效的空string。

事实上,在一些情况下, null将被视为一个合法的空string,而其他字符则不会。 不是非常有帮助的情况,而是程序员应该注意的一个情况。 通常,如果stringValuenull ,那么stringValueforms的expression式将失败,但是大多数接受string作为参数的框架方法和运算符都将null视为空string。

'+'是一个中缀运算符。 像任何运营商一样,它真的在调用一个方法。 你可以想象一个非中缀版本"wow".Plus(null) == "wow"

实施者已经决定了这样的事情…

 class String { ... String Plus(ending) { if(ending == null) return this; ... } } 

所以..你的例子变成了

 var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123"); // abc123 

这是一样的

 var bob = "abc".Plus("123"); // abc123 

null从来没有成为一个string。 所以null.ToString()null.VoteMyAnswer()没有区别。 ;)

我猜是因为这是一个不涉及任何对象的文字ToString()需要一个object

有人在这个讨论的话题中说过, 你不能从无到有做一个string。 (这是一个很好的短语,因为我认为)。 但是,您可以 :-),如以下示例所示:

 var x = null + (string)null; var wtf = x.ToString(); 

工作正常,并没有抛出exception。 唯一的区别是你需要将一个空值转换成一个string – 如果你删除(string)转换 ,那么这个例子仍然编译,但是会抛出一个运行时exception:“运算符+”在input'<null>'和'<null>'“。

注意在上面的代码示例中,x的值不是您可能期望的,它在将其中一个操作数转换为string后实际上是一个空string。


另一个有趣的事实是,在C#/ .NET中如果考虑不同的数据types, null的处理方式并不总是相同的 。 例如:

 int? x = 1; // string x = "1"; x = x + null + null; Console.WriteLine((x==null) ? "<null>" : x.ToString()); 

关于代码片段的第一行 :如果x是包含值1的可为空的整数variables(即int? ),则返回结果<null> 。 如果它是一个值为"1"的string(如注释中所示),那么您将返回"1"而不是<null>

NB也有趣:如果你使用var x = 1; 对于第一行,那么你会得到一个运行时错误。 为什么? 因为赋值会将variablesx转换为不可为空的数据typesint 。 编译器不会假设int? 在这里,因此在添加null的第二行失败。

null添加到string将被忽略。 null (在你的第二个例子中)不是任何对象的实例,所以它甚至没有ToString()方法。 这只是一个文字。

因为串联string时, string.Emptynull之间没有区别。 您也可以将null传递给string.Format 。 但是你试图调用一个null的方法,这总是会导致一个NullReferenceException ,因此会产生一个编译器错误。
如果由于某种原因,你真的想要这样做,你可以写一个扩展方法,检查null ,然后返回string.Empty 。 但是像这样的扩展只能在绝对必要时使用(在我看来)。

一般情况:根据规范,它可能有效也可能不会有效接受null作为参数,但在null上调用方法总是无效的。


这是和其他话题,为什么+操作符的操作数可以是空string的情况下。 这是有点VB的东西(对不起,伙计们)让程序员生活更容易,或假设程序员不能处理空值。 我完全不同意这个规范。 “未知”+“任何事物”应该仍然是“未知的”…