我知道使用string.format会装箱某些对象,那么当只是连接字符串时是否也会如此呢?

4

我正在学习拳击和 string.format()。我发现它会将值类型(如整数)装箱。

因此,以下代码将导致装箱:

var number = 5;
var sampleString = string.Format("The number 5: {0}", number);

这段代码将会生成一个字符串。
The number 5: 5

然而,如果我使用标准的+操作符拼接字符串,它仍然会产生相同的字符串。
var sampleString = "The number 5: " + number;

这是怎么回事,它也将整数转换为对象吗?

这也适用于日期对象,例如:

var dateString = string.Format("The date: {0}", DateTime.Now);
var dateString = "The date: " + DateTime.Now;

我想第一行会分裂,但第二行也会吗?


1
是的,这被转换为一个String.Concat()调用,它需要.ToString(),而.ToString()需要一个对象。 - Alex K.
以下是一篇很好的文章,解释并展示了这个问题:http://jeffbarnes.net/blog/post/2006/08/08/Avoid-Boxing-When-Using-StringFormat-with-Value-Types.aspx - Random Dev
那篇文章是让我开始走上这条路的。但它特别讲解了string.format,我想知道的是标准运算符是否适用相同的规则。区别在于string.format不期望字符串,而是期望对象,但+期望字符串。 - Smeegs
@CarstenKönig:在这篇文章中,通过调用ToString来避免了装箱操作,但是在这里并没有调用。 - Meta-Knight
二进制 +任何非字符串参数都将通过调用从类型对象继承的虚拟 ToString 方法转换为其字符串表示形式 - Alex K.
1个回答

4

针对:var dateString = "The date: " + DateTime.Now;

+将转化为String.Concat方法,您的代码中将会调用string.Concat(object,object) 方法重载。这将导致值类型 DateTime.Now 被装箱成对象。

查看生成的IL代码。

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       55 (0x37)
  .maxstack  2
  .locals init ([0] string dateString0,
           [1] string dateString1)
  IL_0000:  ldstr      "The date: {0}"
  IL_0005:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
  IL_000a:  box        [mscorlib]System.DateTime
  IL_000f:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0014:  stloc.0
  IL_0015:  ldstr      "The date: "
  IL_001a:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
  IL_001f:  box        [mscorlib]System.DateTime
  IL_0024:  call       string [mscorlib]System.String::Concat(object,
                                                              object)
  IL_0029:  stloc.1
  IL_002a:  ldloc.0
  IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0030:  ldloc.1
  IL_0031:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0036:  ret
} // end of method Program::Main

正如您在IL中所看到的,字符串连接被翻译为调用

  IL_0024:  call       string [mscorlib]System.String::Concat(object,
                                                              object)

下面是生成的IL代码:

static void Main(string[] args)
{
    var dateString0 = string.Format("The date: {0}", DateTime.Now);
    var dateString1 = "The date: " + DateTime.Now;
    Console.WriteLine(dateString0);
    Console.WriteLine(dateString1);
}

使用 String.Format 时也会发生装箱操作。


1
啊,谢谢。string.Concat调用需要两个对象,这就是string.format所做的。这就是我迷失的地方。我试图阅读运算符相关的内容,但没有找到任何指向string.Concat的东西。 - Smeegs
我认为这适用于任何值类型,例如整数。 - Smeegs
非常感谢您的额外努力并发布生成的IL代码。等待期结束后,我会接受这个答案。 - Smeegs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接