这是有效的C#代码
var bob = "abc" + null + null + null + "123"; // abc123
这是无效的C#代码
var wtf = null.ToString(); // compiler error
为什么第一个陈述有效?
class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
这是有效的C#代码
var bob = "abc" + null + null + null + "123"; // abc123
这是无效的C#代码
var wtf = null.ToString(); // compiler error
为什么第一个陈述有效?
class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Answers:
第一个工作的原因:
从MSDN:
在字符串连接操作中,C#编译器将空字符串与空字符串相同,但是不会转换原始空字符串的值。
有关+二进制运算符的更多信息:
当一个或两个操作数的类型为string时,binary +运算符将执行字符串连接。
如果字符串连接的操作数为null,则替换为空字符串。否则,通过调用
ToString
从类型对象继承的虚拟方法,任何非字符串参数都将转换为其字符串表示形式。如果
ToString
返回null
,则替换为空字符串。
秒内出错的原因是:
null(C#参考) -null关键字是一种表示空引用的文字,它不引用任何对象。null是引用类型变量的默认值。
wtf = ((String)null).ToString();
自从我使用C#以来,我最近在Java中工作,可以转换为null。
null.ToString()
VS ToString(null)
。
因为+
C#中的运算符在内部转换为String.Concat
,这是一种静态方法。而且这种方法碰巧null
像一个空字符串一样对待。如果您String.Concat
在Reflector中查看源代码,您将看到它:
// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array
(MSDN也提到了它:http : //msdn.microsoft.com/zh-cn/library/k9c94ey1.aspx)
另一方面,ToString()
是无法调用的实例方法null
(应将哪种类型用于null
?)。
+
C#中字符串的运算符只是的语法糖String.Concat
。
__arglist
和一个params
对象数组版本。
Concat
在给定非空字符串数组的情况下始终创建一个新的非空字符串数组,还是发生了其他情况?
第一个样本将被翻译为:
var bob = String.Concat("abc123", null, null, null, "abs123");
该Concat
方法检查输入并将null转换为空字符串
所述第二样品将被翻译成:
var wtf = ((object)null).ToString();
所以null
这里会产生一个参考异常
AccessViolationException
将抛出:)
((object)null).ToString()
=> AccessViolation
((object)1 as string).ToString()
=>NullReference
((object)null).ToString()
里面try/catch
我得到NullReferenceException
了。
您的代码的第一部分就像在中一样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引用的文字,它不引用任何对象。null是引用类型变量的默认值。
“ ToString()
”是可以由对象实例而不是任何文字调用的方法。
String.Empty
不等于null
。在某些方法中,它只是以相同的方式处理String.Concat
。例如,如果您将一个字符串变量设置为null
,String.Empty
则尝试在其上调用方法时,C#不会将其替换为。
null
不会像String.Empty
C#那样被对待,只是像中的一样对待String.Concat
,这就是C#编译器在添加字符串时调用的内容。"abc" + null
转换为String.Concat("abc", null)
,并在内部将该方法替换null
为String.Empty
。第二部分是完全正确的。
在.net之前的COM框架中,任何接收到字符串的例程都必须在完成后释放它。由于将空字符串传入和传出例程非常普遍,并且由于尝试“释放”空指针被定义为合法的不执行操作,因此Microsoft决定使用空字符串指针来表示空字符串。
为了与COM兼容,.net中的许多例程会将空对象解释为合法表示形式的空字符串。通过对.net及其语言进行一些细微更改(最显着的是允许实例成员指示“不要以虚拟方式调用”),Microsoft可以使null
声明为String类型的对象的行为更像是空字符串。如果Microsoft这样做了,那么它也将不得不做Nullable<T>
一些不同的工作(以便允许- Nullable<String>
无论如何恕我直言,他们应该做些什么)和/或定义一个NullableString
类型,该类型基本上可以与互换String
,但不会将其视为null
作为有效的空字符串。
实际上,在某些情况下,a null
将被视为合法的空字符串,而在另一些情况下则不会。这不是一个非常有用的情况,而是程序员应该注意的情况。通常,stringValue.someMember
如果stringValue
is为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()
。;)
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");
。运算符重载是静态方法,其核心是:msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx是不是,var bob = null + "abc";
或者特别string bob = null + null;
是无效的。
我猜是因为它是一个不引用任何对象的文字。ToString()
需要一个object
。
有人在此讨论线程中说,您不能一无所有。 (我认为这是一个很好的短语)。但是可以-您可以 :-),如以下示例所示:
var x = null + (string)null;
var wtf = x.ToString();
工作正常,根本不引发异常。唯一的区别是您需要将一个空值强制转换为字符串-如果删除(string)强制转换,则示例仍会编译,但会引发运行时异常:“运算符'+'在操作数的键入“ <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?
包含value 的可为空的整数变量(即)1
,那么您将获得结果<null>
。如果它是一个带有value的字符串(如注释中所示)"1"
,那么您将"1"
返回而不是<null>
。
NB也很有趣:如果您使用var x = 1;
的是第一行,那么您会遇到运行时错误。为什么?因为赋值会将变量x
转换为数据类型int
,该数据类型不能为空。编译器不在int?
此处假设,因此在null
添加第二行时失败。
null.ToString()
给你起个名字很特别wtf
。为什么会让您感到惊讶?当您一无所有要调用实例方法时,就无法调用它。