c# - KeyValuePair<TKey, TValue>.ToString 实现细节

标签 c# .net tostring keyvaluepair

最近在做其他事情时,我在 KeyValuePair<TKey, TValue>.ToString() implementation 上遇到了一段有点奇怪的代码.

public override string ToString()
{
    StringBuilder stringBuilder = StringBuilderCache.Acquire(16);
    stringBuilder.Append('[');
    if (this.Key != null)
    {
        StringBuilder arg_33_0 = stringBuilder;
        TKey tKey = this.Key;
        arg_33_0.Append(tKey.ToString());
    }
    stringBuilder.Append(", ");
    if (this.Value != null)
    {
        StringBuilder arg_67_0 = stringBuilder;
        TValue tValue = this.Value;
        arg_67_0.Append(tValue.ToString());
    }
    stringBuilder.Append(']');
    return StringBuilderCache.GetStringAndRelease(stringBuilder);
}

跳过 StringBuilderCache类的使用(这是 .NET 本身性能改进的一个很好的例子)我有一个问题:

为什么是

    if (this.Key != null)
    {
        StringBuilder arg_33_0 = stringBuilder;
        TKey tKey = this.Key;
        arg_33_0.Append(tKey.ToString());
    }

更好

    if(this.Key != null)
    {
        stringBuilder.Append(this.Key.ToString());
    }

?

分配新的局部变量而不是直接使用实例有什么好处?

最佳答案

根据 Reference Source 的原始 C# 代码是:

public override string ToString() { 
    StringBuilder s = StringBuilderCache.Acquire(); 
    s.Append('[');
    if( Key != null) { 
        s.Append(Key.ToString());
    }
    s.Append(", ");
    if( Value != null) { 
       s.Append(Value.ToString());
    } 
    s.Append(']'); 
    return StringBuilderCache.GetStringAndRelease(s);
} 

根据 ILspy 的方法的 IL 代码是:

.method public hidebysig virtual 
    instance string ToString () cil managed 
{
    .custom instance void __DynamicallyInvokableAttribute::.ctor() = (
        01 00 00 00
    )
    // Method begins at RVA 0x5f79c
    // Code size 125 (0x7d)
    .maxstack 2
    .locals init (
        [0] class System.Text.StringBuilder,
        [1] !TKey,
        [2] !TValue
    )

    IL_0000: ldc.i4.s 16
    IL_0002: call class System.Text.StringBuilder System.Text.StringBuilderCache::Acquire(int32)
    IL_0007: stloc.0
    IL_0008: ldloc.0
    IL_0009: ldc.i4.s 91
    IL_000b: callvirt instance class System.Text.StringBuilder System.Text.StringBuilder::Append(char)
    IL_0010: pop
    IL_0011: ldarg.0
    IL_0012: call instance !0 valuetype System.Collections.Generic.KeyValuePair`2<!TKey, !TValue>::get_Key()
    IL_0017: box !TKey
    IL_001c: brfalse.s IL_0039

    IL_001e: ldloc.0
    IL_001f: ldarg.0
    IL_0020: call instance !0 valuetype System.Collections.Generic.KeyValuePair`2<!TKey, !TValue>::get_Key()
    IL_0025: stloc.1
    IL_0026: ldloca.s 1
    IL_0028: constrained. !TKey
    IL_002e: callvirt instance string System.Object::ToString()
    IL_0033: callvirt instance class System.Text.StringBuilder System.Text.StringBuilder::Append(string)
    IL_0038: pop

    IL_0039: ldloc.0
    IL_003a: ldstr ", "
    IL_003f: callvirt instance class System.Text.StringBuilder System.Text.StringBuilder::Append(string)
    IL_0044: pop
    IL_0045: ldarg.0
    IL_0046: call instance !1 valuetype System.Collections.Generic.KeyValuePair`2<!TKey, !TValue>::get_Value()
    IL_004b: box !TValue
    IL_0050: brfalse.s IL_006d

    IL_0052: ldloc.0
    IL_0053: ldarg.0
    IL_0054: call instance !1 valuetype System.Collections.Generic.KeyValuePair`2<!TKey, !TValue>::get_Value()
    IL_0059: stloc.2
    IL_005a: ldloca.s 2
    IL_005c: constrained. !TValue
    IL_0062: callvirt instance string System.Object::ToString()
    IL_0067: callvirt instance class System.Text.StringBuilder System.Text.StringBuilder::Append(string)
    IL_006c: pop

    IL_006d: ldloc.0
    IL_006e: ldc.i4.s 93
    IL_0070: callvirt instance class System.Text.StringBuilder System.Text.StringBuilder::Append(char)
    IL_0075: pop
    IL_0076: ldloc.0
    IL_0077: call string System.Text.StringBuilderCache::GetStringAndRelease(class System.Text.StringBuilder)
    IL_007c: ret
} // end of method KeyValuePair`2::ToString

如您所见,只有一个 StringBuilder 类型的局部变量。

变量 arg_33_0arg_67_0 是您使用的反编译器的产物;它们既不在原始 C# 代码中,也不在编译后的 IL 代码中。

关于c# - KeyValuePair<TKey, TValue>.ToString 实现细节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18172596/

相关文章:

c# - 检查只读查询字符串

.net - 从 .Net 调用 FoxPro 报告

api - Node.js 阻止函数检查 (toString)

c# - 为什么 .NET decimal.ToString(string) 从零舍入,显然与语言规范不一致?

c# - 更频繁的 Windows 10 UWP 后台 GPS 跟踪

c# - (WPF 的)窗口可以知道它是否是由 ShowDialog() 打开的吗?

.net - 生成随机 X 长度字符串

c# - 为什么 object.ToString() 没有反函数?

c# - 捕获左/右软键按下——C# .net CF 3.5

c# - 使用 DateTime 格式化问题日期