为什么连接空字符串有效但不调用“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.Emptynull之间没有区别。您也可以将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.someMemberstringValuenull形式的表达式将会失败,但是大多数接受字符串作为参数的框架方法和运算符都会将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 获取调用返回空字符串

在堆上调用类(空字符串错误)C++

算法双指针算法 ( 有效回文串 II )

在 Java 中连接空字符串的正确方法是啥?

2021-10-12:验证回文串。给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。说明:本题中,我们将空字符串定义为有效的回文串 。输入: “A man, a plan

参数“documentPath”的值不是有效的资源路径。路径必须是非空字符串