下面发生了什么?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class DotNetPad
{
public static void Main(string[] args)
{
int i = 10;
string k = "Test";
Console.WriteLine(i+k);
Console.WriteLine(k+i);
}
}
在这两种情况下, i
都被转换为字符串。我对运算符优先级的概念感到困惑(虽然这个例子没有显示出很多)和评估方向。有时评估从左到右进行,反之亦然。我并不确切知道如何评估表达式的科学......
为什么i
在上面的示例中转换为字符串,而实际上没有给出编译错误?
答案 0 :(得分:23)
来自C#规范 - 第7.7.4节“加法运算符:
”字符串连接:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
当一个或两个时,binary +运算符执行字符串连接 操作数是字符串类型。如果字符串连接的操作数是 null,替换空字符串。否则,任何非字符串 通过调用,将参数转换为其字符串表示形式 从类型对象继承的虚拟ToString方法。如果ToString 返回null,替换为空字符串。
答案 1 :(得分:18)
我对运营商优先级和评估方向的想法感到困惑。
不,你不是。这经常被混淆,是的,但这不是你困惑的事情,因为评估的优先级和顺序都不是相关关于整数是否转换为字符串的问题,或者为什么它是合法的将一个整数添加到字符串中。
首先让您不必理解您声称对此感到困惑的观点,规则很简单:
为了做到这一点,你需要知道的全部内容。假设Q()返回一个带有setter的索引器的对象,其他方法都返回整数:
Q()[R()] = A() * B() + C() / D();
根据优先级和关联性括号括起来:
Q()[R()] = ( ( A() * B() ) + ( C() / D() ) );
现在每个子表达式都是从左到右进行评估的。 每个子表达式,包括本身具有子表达式的子表达式。所以这等同于程序:
var q = Q();
var r = R();
var a = A();
var b = B();
var t1 = a * b;
var c = C();
var d = D();
var t2 = c / d;
var t3 = t1 + t2;
最后使用索引r和值t3调用q上的索引setter。
请注意,左侧的每个子表达式左侧的每个子表达式都会在每个子表达式之前进行评估。 A() * B()
留下C() / D()
,因此首先发生。
这与你的问题没有任何关系。你的问题是基于一种误解。
我想知道为什么我在上面的示例中转换为字符串,而不是实际上给出编译错误
这是你的误解。 i
不正在转换为字符串。它正在转换为object
。您的计划完全等同于:
int i = 10;
string k = "Test";
string t1 = System.String.Concat((object)i, (string)k);
Console.WriteLine(t1);
string t2 = System.String.Concat((string)k, (object)i);
Console.WriteLine(t2);
正如您所看到的,首先没有从i
到字符串的转换。 i
通过装箱转换转换为对象,然后传递给String.Concat
方法。然后该方法在盒装整数上调用object.ToString()
。
所以处理上半部分:
我想知道为什么我在上面的示例中转换为字符串,而不是实际上给出编译错误
下半部分是:为什么没有编译错误?
为什么会出现编译错误? C#规范说你可以将任何字符串添加到任何对象,或任何对象添加到任何字符串。 int是一个对象,因此您可以将其添加到字符串中。
答案 2 :(得分:8)
在这两种情况下,你都有+
运算符,字符串为一个的操作数。没有涉及重载的用户定义运算符,因此编译器将使用这两者作为字符串连接情况。
据我所知,C#编译器不会对x + y
的场景使用字符串连接,其中 x
或y
是编译时的string
表达式,如果存在用户定义的重载,例如XName operator +(XNamespace, string)
运算符。
答案 3 :(得分:0)
实际上“+”运算符用于连接。在int和string之间进行连接将产生一个字符串(自动将int转换为字符串)