【问题标题】:Avoidable boxing in string interpolation字符串插值中可避免的装箱
【发布时间】:2022-05-07 17:53:03
【问题描述】:

使用字符串插值使我的字符串格式看起来更加清晰,但是如果我的数据是值类型,我必须添加 .ToString() 调用。

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

var person = new Person { Name = "Tom", Age = 10 };
var displayText = $"Name: {person.Name}, Age: {person.Age.ToString()}";

.ToString() 使格式更长更丑。我试图摆脱它,但string.Format 是一个内置的静态方法,我无法注入它。你对此有什么想法吗?而且既然字符串插值是string.Format的语法糖,为什么他们在生成语法糖后面的代码时不添加.ToString()调用呢?我认为这是可行的。

【问题讨论】:

标签: c# .net string string-interpolation


【解决方案1】:

我不明白如何避免编译器的装箱。 string.Format 的行为不是 C# 规范的一部分。你不能指望它会调用Object.ToString()。事实上它没有:

using System;
public static class Test {
    public struct ValueType : IFormattable {
        public override string ToString() => "Object.ToString";
        public string ToString(string format, IFormatProvider formatProvider) => "IFormattable.ToString";
    }
    public static void Main() {
        ValueType vt = new ValueType();
        Console.WriteLine($"{vt}");
        Console.WriteLine($"{vt.ToString()}");
    }
}

【讨论】:

    【解决方案2】:

    随着最近发布的 C# 10 和 .NET 6,情况发生了变化。编译器已经过优化,可以更好地处理插值字符串。我在这里写的内容来自post by Stephen Toub

    本质上:早期版本的 .NET 将插入的字符串 $"{major}.{minor}.{build}.{revision}"(所有变量都是整数)翻译成类似这样的内容

    var array = new object[4];
    array[0] = major;
    array[1] = minor;
    array[2] = build;
    array[3] = revision;
    string.Format("{0}.{1}.{2}.{3}", array);
    

    从 C#10 开始,编译器可以使用“内插字符串处理程序”。上面的字符串可以翻译成:

    var handler = new DefaultInterpolatedStringHandler(literalLength: 3, formattedCount: 4);
    handler.AppendFormatted(major);
    handler.AppendLiteral(".");
    handler.AppendFormatted(minor);
    handler.AppendLiteral(".");
    handler.AppendFormatted(build);
    handler.AppendLiteral(".");
    handler.AppendFormatted(revision);
    return handler.ToStringAndClear();
    

    据作者说,它不仅消除了对装箱的需求,而且还引入了进一步的增强功能。因此,新方法实现了“40% 的吞吐量提升和几乎 5 倍的内存分配减少”(Stephen Toub)。

    而这只是冰山一角。除了内插字符串处理程序之外,C#10 还引入了内插字符串解释方面的进一步优化。

    因此,我不再过于担心性能,而是专注于清晰度和可读性。很可能我们花费大量时间试图以代码清晰为代价超越编译器,却没有取得任何实质性的成果。我想说,除非我们遇到严重的性能问题,否则我们可以使用插值字符串而无需走复杂的弯路。

    限制。当我们翻译字符串时,情况可能会有所不同。那么我们的格式字符串就变成了动态资源,对吧?现在编译器无法在运行前解释字符串,我们又回到了string.Format

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-17
      • 1970-01-01
      相关资源
      最近更新 更多