为什么连接空字符串有效但不调用“null.ToString()”?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么连接空字符串有效但不调用“null.ToString()”?相关的知识,希望对你有一定的参考价值。
这是有效的C#代码
var bob = "abc" + null + null + null + "123"; // abc123
这不是有效的C#代码
var wtf = null.ToString(); // compiler error
为什么第一个声明有效?
第一个工作的原因:
来自MSDN:
在字符串连接操作中,C#编译器将空字符串视为空字符串,但它不会转换原始空字符串的值。
有关+ binary operator的更多信息:
当一个或两个操作数的类型为字符串时,binary +运算符执行字符串连接。
如果字符串连接的操作数为null,则替换空字符串。否则,通过调用从类型object继承的虚拟
ToString
方法,将任何非字符串参数转换为其字符串表示形式。如果
ToString
返回null
,则替换空字符串。
第二个错误的原因是:
null (C# Reference) - null关键字是一个表示空引用的文字,一个不引用任何对象的引用。 null是引用类型变量的默认值。
因为当你串起弦乐时,string.Empty
和null
之间没有区别。您也可以将null传递给string.Format
。但是你试图在null
上调用一个方法,它总是会产生NullReferenceException
,因此会产生编译器错误。
如果由于某种原因你真的想要这样做,你可以写一个扩展方法,检查null
然后返回string.Empty
。但是这样的扩展只应在绝对必要时使用(在我看来)。
通常:根据规范,它可能会或可能不会将null作为参数接受,但在null上调用方法始终无效。
这是和其他主题为什么+运算符的操作数在字符串的情况下可以为null。这是一个VB的事情(对不起家伙)让程序员生活更轻松,或者假设程序员无法处理空值。我完全不同意这个规范。 '未知'+'任何'应该仍然'未知'......
因为C#中的+
运算符内部转换为String.Concat
,这是一种静态方法。而这种方法恰好将null
视为一个空字符串。如果你看一下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
上调用(null
应该使用哪种类型?)。
第一个样本将被翻译成:
var bob = String.Concat("abc123", null, null, null, "abs123");
Concat
方法检查输入并将null转换为空字符串
第二个样本将被翻译成:
var wtf = ((object)null).ToString();
因此,这里将生成null
引用异常
您的代码的第一部分就像在String.Concat
中那样对待,
这是C#编译器在添加字符串时调用的内容。 “abc" + null
被翻译成String.Concat("abc", null)
,
在内部,该方法用null
替换String.Empty
。所以,这就是为什么你的第一部分代码不会抛出任何异常。就像
var bob = "abc" + string.Empty + string.Empty + string.Empty + "123"; //abc123
并且在代码的第二部分抛出异常,因为'null'不是对象,null关键字是表示空引用的文字,一个不引用任何对象的引用。 null是引用类型变量的默认值。
'ToString()
'是一种可以被一个对象的实例调用而不是任何文字的方法。
在.net之前的COM框架中,任何接收到字符串的例程都必须在完成它时释放它。因为将空字符串传入和传出例程非常常见,并且因为尝试“释放”空指针被定义为合法的无操作操作,Microsoft决定使用空字符串指针表示空字符串。
为了与COM兼容,.net中的许多例程将空对象解释为合法表示形式为空字符串。通过一些微小的更改.net及其语言(最值得注意的是允许实例成员指示“不要调用为虚拟”),Microsoft可能会使声明类型为String的null
对象的行为更像空字符串。如果微软已经这样做了,它也必须使Nullable<T>
工作方式有所不同(以便允许Nullable<String>
- 他们应该恕我直言所做的事情)和/或定义一个NullableString
类型,它几乎可以与String
互换,但是不会将null
视为有效的空字符串。
事实上,在某种情况下,null
将被视为合法的空字符串,而其他情况则不会。这不是一个非常有用的情况,而是程序员应该意识到的情况。一般来说,如果stringValue.someMember
是stringValue
,null
形式的表达式将会失败,但是大多数接受字符串作为参数的框架方法和运算符都会将null
视为空字符串。
'+'
是一个中缀运营商。像任何运算符一样,它实际上是在调用方法。你可以想象一个非中缀版本"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都不会成为字符串。所以null.ToString()
与null.VoteMyAnswer()
没有什么不同。 ;)
我猜是因为它是一个不引用任何对象的文字。 ToString()
需要一个object
。
有人在这个讨论主题中说,你不能无所作为。 (我认为这是一个很好的短语)。但是 - 是的 - 你可以:-),如下例所示:
var x = null + (string)null;
var wtf = x.ToString();
工作正常,根本不会抛出异常。唯一的区别是你需要将其中一个空值转换为一个字符串 - 如果删除(字符串)强制转换,那么该示例仍然会编译,但会抛出一个运行时异常:“运算符'+'在操作数上是不明确的输入'<null>'和'<null>'“。
注:在上面的代码示例中,x的值不是您可能期望的null,在将其中一个操作数转换为字符串后,它实际上是一个空字符串。
另一个有趣的事实是,在C#/ .NET中,如果考虑不同的数据类型,null
的处理方式并不总是相同的。例如:
int? x = 1; // string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());
注意代码片段的第一行:如果x
是一个包含值int?
的可以为空的整数变量(即1
),那么你将得到结果<null>
。如果它是一个字符串(如注释中所示),其值为"1"
,那么你将获得"1"
而不是<null>
。
注:同样有趣的是:如果您在第一行使用var x = 1;
,那么您将收到运行时错误。为什么?因为赋值会将变量x
转换为数据类型int
,这是不可为空的。编译器在这里不假设int?
,因此在添加null
的第二行失败。
将null
添加到字符串中只是被忽略了。 null
(在你的第二个例子中)不是任何对象的实例,因此它甚至没有ToString()
方法。这只是一个文字。
以上是关于为什么连接空字符串有效但不调用“null.ToString()”?的主要内容,如果未能解决你的问题,请参考以下文章
调用 ASP.Net WebAPI 端点时,JavaScript 获取调用返回空字符串
2021-10-12:验证回文串。给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。说明:本题中,我们将空字符串定义为有效的回文串 。输入: “A man, a plan