为什么它是有效连接空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.Empty
replacenull
。 所以,这就是为什么你的第一部分代码不会抛出任何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所做的事情)和/或定义一个NullableString
types,与String
可互换,但不会将null
视为有效的空string。
事实上,在一些情况下, null
将被视为一个合法的空string,而其他字符则不会。 不是非常有帮助的情况,而是程序员应该注意的一个情况。 通常,如果stringValue
为null
,那么stringValue
forms的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.Empty
和null
之间没有区别。 您也可以将null传递给string.Format
。 但是你试图调用一个null
的方法,这总是会导致一个NullReferenceException
,因此会产生一个编译器错误。
如果由于某种原因,你真的想要这样做,你可以写一个扩展方法,检查null
,然后返回string.Empty
。 但是像这样的扩展只能在绝对必要时使用(在我看来)。
一般情况:根据规范,它可能有效也可能不会有效接受null作为参数,但在null上调用方法总是无效的。
这是和其他话题,为什么+操作符的操作数可以是空string的情况下。 这是有点VB的东西(对不起,伙计们)让程序员生活更容易,或假设程序员不能处理空值。 我完全不同意这个规范。 “未知”+“任何事物”应该仍然是“未知的”…