9

下面发生了什么?

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在上面的例子中被转换为字符串,而实际上并没有给出编译错误?

4

4 回答 4

23

来自 C# 规范 - 第 7.7.4 节加法运算符:

字符串连接

string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);

一个或两个 操作数都是字符串类型时,二元 + 运算符执行字符串连接。如果字符串连接的操作数为 null,则替换为空字符串。否则,通过调用从类型 object 继承的虚拟 ToString 方法,将任何非字符串参数转换为其字符串表示形式。如果 ToString 返回 null,则替换为空字符串。

于 2012-05-02T13:58:25.863 回答
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 上的索引设置器。

请注意,左侧的每个子表达式都在右侧的每个子表达式之前进行评估。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 是一个对象,因此您可以将其添加到字符串中。

于 2012-05-02T15:16:17.420 回答
8

在这两种情况下,您都拥有+将字符串作为操作数之一的运算符。没有涉及重载的用户定义运算符,因此编译器将使用这两种作为字符串连接的情况。

据我所知,如果存在用户定义的重载(例如运算符),C# 编译器只会在编译时x + ywhere or is a expression 的情况下不使用 字符串连接。xystringXName operator +(XNamespace, string)

于 2012-05-02T13:57:12.567 回答
0

实际上,“+”运算符用于连接。在 int 和 string 之间进行连接将给出一个字符串(自动将 int 转换为字符串)

于 2012-05-02T14:04:52.007 回答