C# 其中哪一个性能更好?
这两种说法有什么区别?就性能而言,哪一个更好C# 其中哪一个性能更好?,c#,performance,C#,Performance,这两种说法有什么区别?就性能而言,哪一个更好 Console.Writeline(i); Console.Writeline(i.toString()); 其中i是一个字符串或整数。底线是,写入控制台肯定会主导这里的性能-即使您将其重定向到某种“null”接收器 在我看来,区别在于 Console.WriteLine(i); 更容易阅读。。。因此,在我证明使用可读性稍差的表单会带来具体的好处之前,我会一直这么做。在这种情况下,当它是整数时,两个表单都不会装箱i,因为WriteLine(int
Console.Writeline(i);
Console.Writeline(i.toString());
其中i是一个字符串或整数。底线是,写入控制台肯定会主导这里的性能-即使您将其重定向到某种“null”接收器 在我看来,区别在于
Console.WriteLine(i);
更容易阅读。。。因此,在我证明使用可读性稍差的表单会带来具体的好处之前,我会一直这么做。在这种情况下,当它是整数时,两个表单都不会装箱i
,因为WriteLine(int)
有一个重载。在这两行文字之间有一个稍微有趣的问题:
Console.WriteLine("Some format {0} stuff", i);
Console.WriteLine("Some format {0} stuff", i.ToString());
第一种形式是将整数装箱;第二个不会。性能上的差异 没有实际区别,两者都将调用ToString将数字转换为字符串。应该没有区别。如果您自己没有显式地调用ToString()方法,那么Console.WriteLine方法应该自动调用该方法。然而,如果你看一下IL代码,我惊讶地发现它们并不完全相同。显然,Console.Writeline(int)必须在内部将int转换为十进制字符字符串,但从IL 对于此代码:
static void Main(string[] args)
{
int i = 34;
Console.WriteLine(i);
Console.WriteLine(i.ToString());
}
IL是
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] int32 i)
L_0000: nop
L_0001: ldc.i4.s 0x22
L_0003: stloc.0
L_0004: ldloc.0
L_0005: call void [mscorlib]System.Console::WriteLine(int32)
L_000a: nop
L_000b: ldloca.s i
L_000d: call instance string [mscorlib]System.Int32::ToString()
L_0012: call void [mscorlib]System.Console::WriteLine(string)
L_0017: nop
L_0018: ret
}
使用Jon的示例(带string.format),第一种情况(不带ToString()
)的值已装箱。。。
代码:
IL是
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 i)
L_0000: nop
L_0001: ldc.i4.s 0x22
L_0003: stloc.0
L_0004: ldstr "Some format {0} stuff"
L_0009: ldloc.0
L_000a: box int32
L_000f: call string [mscorlib]System.String::Format(string, object)
L_0014: call void [mscorlib]System.Console::WriteLine(string)
L_0019: nop
L_001a: ldstr "Some format {0} stuff"
L_001f: ldloca.s i
L_0021: call instance string [mscorlib]System.Int32::ToString()
L_0026: call string [mscorlib]System.String::Format(string, object)
L_002b: call void [mscorlib]System.Console::WriteLine(string)
L_0030: nop
L_0031: ret
}
首先,优化到这个水平并不会给你带来任何好处。优化您的算法,然后配置文件,并优化瓶颈。我会关注哪一个更具可读性和可维护性(在这两种情况下,我更喜欢第一个…)
但是,从性能的角度来看,第一个通常会更好。如果用int调用第一个,它实际上调用第二个。对于字符串,您将得到一个额外的(无操作)方法调用。如果“i”是值类型的实例,而不是.Net原语,则在这种情况下会有所不同。在这种情况下,它将装箱该值以调用WriteLine(对象)覆盖。直接对值类型调用ToString()不应导致出现框IIRC@JaredPar-只要值类型覆盖
对象,就不会发生装箱。ToString
。我做了测试,编辑了答案。。。看看我。。。没有装箱,而且令人惊讶的是,也没有显式调用ToString()。当然,它们并不相同,您调用的是两个不同的方法。它们最终都以相同的设置调用ToString,但它们的方式并不完全相同。@Guffa(因为您使用短语“当然”),在第一种情况下,您调用的是相同的方法(WriteLine()
)。怀疑编译器可能会将其转换为对ToString()的调用并不是不合理的,就像您自己调用了它一样。。。(C#编译器已经为您完成了许多其他类似的语法翻译)在这种情况下,IL将是相同的…我还要补充一点,您不可能在严格的性能限制循环中写入控制台-这通常是唯一会出现性能差异的地方。
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 i)
L_0000: nop
L_0001: ldc.i4.s 0x22
L_0003: stloc.0
L_0004: ldstr "Some format {0} stuff"
L_0009: ldloc.0
L_000a: box int32
L_000f: call string [mscorlib]System.String::Format(string, object)
L_0014: call void [mscorlib]System.Console::WriteLine(string)
L_0019: nop
L_001a: ldstr "Some format {0} stuff"
L_001f: ldloca.s i
L_0021: call instance string [mscorlib]System.Int32::ToString()
L_0026: call string [mscorlib]System.String::Format(string, object)
L_002b: call void [mscorlib]System.Console::WriteLine(string)
L_0030: nop
L_0031: ret
}