【问题标题】:C# Anonymous type `ToString` complicated? [closed]C#匿名类型`ToString`复杂? [关闭]
【发布时间】:2020-05-14 23:35:01
【问题描述】:

有谁知道为什么 C# 中的匿名类型对ToString 使用如此复杂的实现?我相信早期版本使用了更简单的StringBuilder 实现。

这是来自 ILSpy 的 ToString 示例:

public override string ToString() {
    object[] array = new object[2];
    <a>j__TPar val = <a>i__Field;
    ref <a>j__TPar reference = ref val;
    <a>j__TPar val2 = default(<a>j__TPar);
    object obj;
    if (val2 == null) {
        val2 = reference;
        reference = ref val2;
        if (val2 == null) {
            obj = null;
            goto IL_0046;
        }
    }
    obj = reference.ToString();
    goto IL_0046;
    IL_0046:
    array[0] = obj;
    <b>j__TPar val3 = <b>i__Field;
    ref <b>j__TPar reference2 = ref val3;
    <b>j__TPar val4 = default(<b>j__TPar);
    object obj2;
    if (val4 == null) {
        val4 = reference2;
        reference2 = ref val4;
        if (val4 == null) {
            obj2 = null;
            goto IL_0081;
        }
    }
    obj2 = reference2.ToString();
    goto IL_0081;
    IL_0081:
    array[1] = obj2;
    return string.Format(null, "{{ a = {0}, b = {1} }}", array);
}

【问题讨论】:

  • 我强烈不同意这是基于意见的,蝙蝠对你来说就是 StackOverflow。有人知道问题的实际情况,甚至可能有一个 Github 问题说明或提交说明更改...
  • 每当?. 运算符应用于不受约束的类型参数时,C# 编译器都会生成带有引用分配的奇怪代码模式。 github.com/icsharpcode/ILSpy/issues/1050
  • @Daniel 谢谢,但我想知道这种模式的理由是什么。

标签: c# .net .net-core roslyn anonymous-types


【解决方案1】:

查看AnonymousTypeMethodBodySynthesizer.AnonymousTypeToStringMethodSymbolblame 似乎是从一开始就通过string.Format 实现Roslyn 编译器。为什么以这种方式实施我不知道。由于它是编译器,我假设考虑了性能和可维护性的原因(而不是生成代码的简单性)。虽然string.Format 内部似乎使用StringBuilder 和一些缓存魔法,但不会说以前的实现更慢或更快。

UPD

似乎在引入Roslyn 之前,编译器确实生成了StrinBuilder 实现。来自 Pro C# 2008 和 .NET 3.5 平台 作者:Andrew Troelsen:

所有匿名类型都自动派生自 System.Object,并提供了 Equals()、GetHashCode() 和 ToString() 的重写版本。 ToString() 实现只是从每个名称/值对构建一个字符串,例如:

public override string ToString()
{
    StringBuilder builder = new StringBuilder(); builder.Append("{ Color = "); 
    builder.Append(this.<Color>i__Field); builder.Append(", Make = "); 
    builder.Append(this.<Make>i__Field); builder.Append(", CurrentSpeed = "); 
    builder.Append(this.<CurrentSpeed>i__Field); builder.Append(" }");
    return builder.ToString();
}

我已经写过small benchmark(虽然不知道它有多正确=),而且旧的实现似乎更快。

还在 github(Generate more efficient anonymous type members) 上发现问题,其中引起了对 ToString 性能的担忧,但在 cmets 中提出了有效问题:

在 ToString 表示中使用匿名类型是否很常见?我怀疑大多数人会在其中之一上调用 ToString。它们将被传递给序列化程序,该序列化程序将执行不同的表示或用作 LINQ 中的分组键。

【讨论】:

  • 由于这个问题不幸被关闭,我会给你接近正确的答案。我确实看到了 github 问题,但我认为这与为什么 ToString 变得如此复杂是相切的,尽管我开始相信这可能是为了在为具体类型构建方法时最小化装箱和/或帮助 JIT 优化在运行时。
  • 顺便说一句,“责备”是什么意思?
  • @NetMage 谢谢。简单的 git blame。
猜你喜欢
  • 1970-01-01
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
相关资源
最近更新 更多