我有一个简单的问题,但我很惊讶。
此代码有效:
int itemID = 1;
string dirPath = @"C:\" + itemID + @"\abc";
在这种情况下,我为什么不必itemID.ToString()
?
答案 0 :(得分:13)
来自MSDN
当一个或两个操作数的类型为字符串时,binary +运算符执行字符串连接。如果字符串连接的操作数为null,则替换空字符串。否则,通过调用从类型对象继承的虚拟ToString方法,将任何非字符串参数转换为其字符串表示形式。如果ToString返回null,则替换空字符串。
根据其他答案中的一些评论,扩展我的答案......
这个过程不仅仅是“语法糖”或方便。它是一个名为Operator Overloading的核心C#语言特性的结果。在+运算符和String +重载的情况下,提供重载作为抽象String类的内部的手段,这是良好设计原则的核心基础。 + String Overload通过确保它永远不会返回空值来提供类型安全性,而是为任何无法使用.ToString()
方法转换的操作数返回空字符串。但是,即使自定义复杂类型(不仅仅是基元)也可以添加到字符串中,假设它们具有.ToString()
重载,而不知道任何不同的String类型的实现。
运算符重载是一种主要语言功能,更多人应该学会利用它的强大功能。
答案 1 :(得分:8)
+
被转换为string.Concat
调用,该调用在每个对象上内部调用无参数ToString
。
该方法通过调用the来连接args中的每个对象 该对象的无参数ToString方法;它没有添加任何 分隔符。
编辑:
以下是ILSpy中的内容
答案 2 :(得分:6)
+运算符有许多重载。其中三个如下:
operator +(string a,string b)
operator +(string a,object b)
operator +(对象a,字符串b)
您的代码正在使用运算符的第二个重载。
该运算符在被确定为匹配后,将其转换为对string.Concat
的调用,该调用可以将任意数量的对象(类型为object
)作为其参数。
在string.Concat
的定义中,它将在所有参数上调用ToString
(在首先检查它们之后)以获取它们的字符串值,这就是将要连接的内容。
由于所有这一切,您始终可以使用字符串连接任何对象,并使用该对象的ToString
方法进行编译和执行。
答案 3 :(得分:1)
因为它是由编译器自动完成的。
基本上:
string a = "abc" + 1;
编译为:
string a = string.Concat((object)"abc", (object)1);
这仅仅是语法糖。 虽然我个人不希望自动转换。
Concat
的参考:
http://msdn.microsoft.com/en-us/library/kbseaaft.aspx
答案 4 :(得分:0)
这是一种语言功能。在使用ToString()
运算符进行字符串连接时,会在内部调用+
。
这个的根本原因仅仅是方便(并且可能由于ToString()
调用较少而增加了可读性,但它也可能诱使你认为对象是一个字符串,实际上它可以是任何东西)显影剂。
对于C#,可能采用了Java的行为,这是相同的。可能有趣的是,问一问为什么这首先是在Java中引入的。
答案 5 :(得分:0)
一个非常有趣的问题。
让我们看一下你的例子的IL代码:
ldstr "C:\\"
ldloc.0
box int
ldstr "\\abc"
call string System.String.Concat(object, object, object)
后面的被调用函数是System.String.Concat,它带有3个对象!
让我们深入了解.NET源代码:
public static String Concat(Object arg0, Object arg1, Object arg2) {
Contract.Ensures(Contract.Result<String>() != null);
Contract.EndContractBlock();
if (arg0 == null)
{
arg0 = String.Empty;
}
if (arg1==null) {
arg1 = String.Empty;
}
if (arg2==null) {
arg2 = String.Empty;
}
return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
}
当你看到ToString()
它会被召唤但稍后会被召唤出来!这对微软的家伙来说非常令人印象深刻!