在C#中,为两种不同的写作方式生成的字节代码有什么不同,我期望是同样的事情:
返回创建的对象:
public MemoryStream GetStream() {
MemoryStream s = new MemoryStream(this.GetBytes());
return s;
}
返回新:
public MemoryStream GetStream() {
return new MemoryStream(this.GetBytes());
}
是否会优化差异?或者第一个比第二个更容易受垃圾收集影响?或者这只是个人偏好?
答案 0 :(得分:1)
查看IL代码,似乎第二个版本中的步骤少于第一个版本。
.method public hidebysig
instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed
{
// Method begins at RVA 0x22c0
// Code size 13 (0xd)
.maxstack 1
.locals init (
[0] class [mscorlib]System.IO.MemoryStream s,
[1] class [mscorlib]System.IO.MemoryStream CS$1$0000
)
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: br.s IL_000b
IL_000b: ldloc.1
IL_000c: ret
} // end of method Form1::GetStream1
.method public hidebysig
instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed
{
// Method begins at RVA 0x22dc
// Code size 11 (0xb)
.maxstack 1
.locals init (
[0] class [mscorlib]System.IO.MemoryStream CS$1$0000
)
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method Form1::GetStream2
它看起来似乎没有更多的地狱,但还有更多的步骤。
@Alexei Levenkov,这是代码的发布版本
.method public hidebysig
instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed
{
// Method begins at RVA 0x2264
// Code size 8 (0x8)
.maxstack 1
.locals init (
[0] class [mscorlib]System.IO.MemoryStream s
)
IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ret
} // end of method Form1::GetStream1
.method public hidebysig
instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed
{
// Method begins at RVA 0x2278
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
IL_0005: ret
} // end of method Form1::GetStream2
似乎还有点多。
答案 1 :(得分:1)
如果您使用Reflector检查为此生成的代码:
public MemoryStream GetStream(byte[] bytes)
{
MemoryStream s = new MemoryStream(bytes);
return s;
}
对于发布版本,您可以获得:
.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
.maxstack 1
.locals init (
[0] class [mscorlib]System.IO.MemoryStream s)
L_0000: ldarg.1
L_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
L_0006: stloc.0
L_0007: ldloc.0
L_0008: ret
}
正如您所看到的,C#编译器已经优化了额外的变量。
但是,对于调试版本,您可以得到:
.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
.maxstack 1
.locals init (
[0] class [mscorlib]System.IO.MemoryStream s,
[1] class [mscorlib]System.IO.MemoryStream CS$1$0000)
L_0000: nop
L_0001: ldarg.1
L_0002: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
L_0007: stloc.0
L_0008: ldloc.0
L_0009: stloc.1
L_000a: br L_000f
L_000f: ldloc.1
L_0010: ret
}
显然编译器无法优化调试构建的额外变量,以防您在调试时检查它。
因此,如果您想将额外的变量保留用于调试目的,那么它很好 - 它对发布版本没有任何影响。
答案 2 :(得分:1)
我相信结果优化的JITed代码将是相同的。
对GC的行为肯定没有影响,因为对象的生命周期将取决于使用返回值的人(你可能会考虑在函数结束之前不再使用值的情况,这显然不是这里的情况 - {{ 1}}在方法执行结束时返回。)
非优化(调试)构建中唯一明显的区别是,您将能够看到s
变量的值。
答案 3 :(得分:0)
这两个代码段 主要 相同,性能差异很小,可以忽略不计,从代码风格和方法功能的角度来看,它们是可以选择的。
如果你的方法除了返回MemoryStream
对象之外不应该做任何其他事情,那么第二个代码片段就足够了,但如果你需要在返回它之前对MemoryStream
对象执行某些操作,必须使用第一个。
垃圾收集方面没有区别。