我对运算符优先级和评估方向的想法感到困惑。
不,你不是。是的,这经常被混淆,但这不是你混淆的事情,因为优先级和评估顺序都与整数是否转换为字符串,或者为什么将整数添加到字符串是合法的问题相关.
为了首先让您对您声称感到困惑的点感到困惑,规则非常简单:
- 表达式根据运算符优先级和关联性加括号。
- 子表达式按从左到右的顺序计算。
这就是你需要知道的所有事情。假设 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 上的索引设置器。
请注意,左侧的每个子表达式都在右侧的每个子表达式之前进行评估。A() * B()
是左边的C() / D()
,所以它首先发生。
这与你的问题无关。你的问题是基于一个误解。
我想知道为什么 i 在上面的示例中被转换为字符串,而实际上并没有给出编译错误
有你的误会。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()
装箱整数。
所以这涉及前半部分:
我想知道为什么 i 在上面的示例中被转换为字符串,而实际上并没有给出编译错误
后半部分是:为什么没有编译错误?
为什么会出现编译错误?C# 规范说您可以将任何字符串添加到任何对象,或将任何对象添加到任何字符串。int 是一个对象,因此您可以将其添加到字符串中。