为什么连接空字符串有效但不调用"null.ToString()"?

sup*_*cal 121 .net c# string null

这是有效的C#代码

var bob = "abc" + null + null + null + "123";  // abc123
Run Code Online (Sandbox Code Playgroud)

这不是有效的C#代码

var wtf = null.ToString(); // compiler error
Run Code Online (Sandbox Code Playgroud)

为什么第一个声明有效?

Pra*_*ana 159

第一个工作的原因:

来自MSDN:

在字符串连接操作中,C#编译器将空字符串视为空字符串,但它不会转换原始空字符串的值.

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

当一个或两个操作数的类型为字符串时,binary +运算符执行字符串连接.

如果字符串连接的操作数为null,则替换空字符串.否则,通过调用ToString从类型object继承的虚方法,将任何非字符串参数转换为其字符串表示形式.

如果ToString返回null,则替换空字符串.

第二个错误的原因是:

null(C#Reference) - null关键字是表示空引用的文字,不引用任何对象.null是引用类型变量的默认值.

  • @Jochem:你还在尝试在null对象上调用一个方法,所以我猜不了.可以把它想象成`null.ToString()`vs`ToString(null)`. (14认同)

Bot*_*000 107

因为+C#中的运算符内部转换为String.Concat静态方法.而这种方法恰好null像空字符串一样对待.如果你看一下String.ConcatReflector 的来源,你会看到它:

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

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

另一方面,ToString()是一个实例方法,你不能调用它null(应该使用什么类型null?).

  • Jon Skeet?那是你吗? (4认同)
  • 尽管如此,String类中没有+运算符.那么编译器是否正在转换为String.Concat? (2认同)

Via*_*ukh 29

一个样本将被翻译成:

var bob = String.Concat("abc123", null, null, null, "abs123");
Run Code Online (Sandbox Code Playgroud)

Concat方法检查输入并将null转换为空字符串

所述第二样品将被翻译成:

var wtf = ((object)null).ToString();
Run Code Online (Sandbox Code Playgroud)

因此,null这里将生成一个引用异常

  • @Ieppie除了不会抛出AccessViolation(为什么会这样?) - 这里是NullReferenceException. (3认同)

Tal*_*lha 11

您的代码的第一部分就是这样处理的String.Concat,

这是C#编译器在添加字符串时调用的内容." abc" + null被翻译成String.Concat("abc", null),

并在内部,该方法取代nullString.Empty.所以,这就是为什么你的第一部分代码不会抛出任何异常.就像

var bob = "abc" + string.Empty + string.Empty + string.Empty + "123";  //abc123
Run Code Online (Sandbox Code Playgroud)

并且在代码的第二部分抛出异常,因为'null'不是对象,null关键字是表示空引用的文字,一个不引用任何对象的引用.null是引用类型变量的默认值.

并且' ToString()'是一种可以由对象的实例调用但不是任何文字的方法.

  • `String.Empty`不等于`null`.它在一些方法中的处理方式与`String.Concat`相同.例如,如果您将字符串变量设置为"null",如果您尝试在其上调用方法,则C#不会将其替换为`String.Empty`. (3认同)
  • 几乎.`null`不被C#称为`String.Empty`,它只是在`String.Concat`中被处理,这是C#编译器在添加字符串时调用的内容.`"abc"+ null`被转换为`String.Concat("abc",null)`,在内部,该方法用`String.Empty`替换`null`.第二部分是完全正确的. (3认同)

sup*_*cat 9

在.net之前的COM框架中,任何接收到字符串的例程都必须在完成它时释放它.因为将空字符串传入和传出例程非常常见,并且因为尝试"释放"空指针被定义为合法的无操作操作,Microsoft决定使用空字符串指针表示空字符串.

为了与COM兼容,.net中的许多例程将空对象解释为合法表示形式为空字符串.通过一些微小的变化.net及其语言(最值得注意的是允许实例成员指示"不要调用为虚拟"),Microsoft可能会使null声明类型String的对象更像空字符串.如果微软已经这样做了,那么它也必须以Nullable<T>不同的方式进行工作(以便允许Nullable<String>- 他们应该恕我直销的那些东西)和/或定义一种NullableString大多数可以互换的类型String,但不会考虑null作为有效的空字符串.

实际上,在某些情况下,a null将被视为合法的空字符串,而其他情况则不会被视为合法的空字符串.这不是一个非常有用的情况,而是程序员应该意识到的情况.通常,stringValue.someMember如果stringValuenull,表单的表达式将失败,但是大多数接受字符串作为参数的框架方法和运算符将null视为空字符串.


Nig*_*rne 5

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

实施者决定了这样的事情......

class String
{
  ...
  String Plus(ending)
  {
     if(ending == null) return this;
     ...
  }
} 
Run Code Online (Sandbox Code Playgroud)

那么......你的榜样就变成了

var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123");  // abc123
Run Code Online (Sandbox Code Playgroud)

这是一样的

var bob = "abc".Plus("123");  // abc123
Run Code Online (Sandbox Code Playgroud)

在任何时候null都不会成为字符串.所以null.ToString()没有什么不同 null.VoteMyAnswer().;)