【问题标题】:Why does boxing occur in the interpolation expression of int?为什么int的插值表达式会出现装箱?
【发布时间】:2020-08-02 01:14:15
【问题描述】:

例如下面的代码:

int n=1;
string str=$"{n}";

但是在显式添加ToString()之后,就不会发生装箱了。

int n=1;
//The compiler will recommend removing the explicit call of the ToString() method
string str=$"{n.ToString()}";

CLR via C#这本书写道String.Format会在内部调用ToString方法来获取对象的字符串表示形式。

既然内部调用了ToString方法,为什么会出现例1中的装箱呢?

【问题讨论】:

  • 相关:123

标签: c# string.format


【解决方案1】:

“呼叫ToString”并不是防止拳击的神奇方法。如果您调用ToString 它已被装箱,装箱仍然会发生,字符串插值就是这种情况。

如您所知,字符串插值通常不适合 string.Format 调用。如果您查看list of overloads available,您会发现没有采用像intlong 这样的值类型的重载。每个重载都需要一个object。要将int 传递给这些方法,首先需要将其装箱。 string.Format 然后在某个时间点调用ToString object

将此与在字符串插值中直接调用ToString 进行比较。没有转换为引用类型 (object),所以没有装箱。

【讨论】:

  • 谢谢~我知道string.Format没有int的重载,但是当我显式使用ToString时,编译器建议去掉ToString方法。这是编译器的问题吗?
  • @yuxing no.您不应该总是以牺牲可读性为代价来使用性能最高的代码。您应该只尝试优化您真正需要的地方。在你并不真正需要的地方,争取可读性。
【解决方案2】:

我注意到,尽管您的代码使用的是 C# 插值字符串,但它并没有使用 FormattedString 类,因为 C# 编译器只会使用 FormattedString 如果插值字符串直接分配给FormattedString-typed 变量、字段或参数(我不同意,但无论如何)。

CLR via C#一书写道,String.Format会在内部调用ToString方法来获取对象的字符串表示形式。

是的,但是所有String.Format 重载都使用Object 类型的参数或params Object[],这必然意味着将其参数装箱。

为什么在示例 1 中会出现装箱?

因为它必须将int n 传递给Object arg0

这是我在 LinqPad(C# 8.0,启用了编译器优化)中编译您的第一个代码块时生成的 IL:

IL_0000:  ldc.i4.1    
IL_0001:  stloc.0     
IL_0002:  ldstr       "{0}"
IL_0007:  ldloc.0     
IL_0008:  box         System.Int32
IL_000D:  call        System.String.Format
IL_0012:  pop         
IL_0013:  ret   

您可以在指令偏移量IL_0008 处看到box 指令,就在它传递到String.Format 之前。

【讨论】:

    【解决方案3】:

    为了格式化一个字符串,它只能接受 Object 类型,它调用 ToString() 来连接它。装箱基本上是将值类型转换为引用类型,这就是隐式转换为对象时发生的事情,因此可以将其存储在堆中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-22
      • 1970-01-01
      相关资源
      最近更新 更多