2013-06-28 90 views
0

在C#中,有没有被写入的两种不同的方式产生的字节代码的任何区别,我所期望的是同一件事:返回新类型和返回对象有区别吗?

返回创建的对象:

public MemoryStream GetStream() { 
    MemoryStream s = new MemoryStream(this.GetBytes()); 
    return s; 
} 

返回新:

public MemoryStream GetStream() { 
    return new MemoryStream(this.GetBytes()); 
} 

是否有任何差异被优化掉?还是第一个比第二个更容易垃圾收集?或者这只是个人偏好?

+2

我想,这是个人喜好。我看不出可以对此代码进行哪些优化。 – shahkalpesh

+1

无论如何编译器会内联整个方法。 –

回答

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

您确定它不是非优化IL(来自调试版本)吗? –

0

两个代码片段是大多相同很少的性能差异可以忽略不计,这是的代码风格和方法的功能的问题由他们选择。 如果你的方法除了返回MemoryStream对象之外不应该做其他事情,那么第二个代码片段就足够了,但是如果你需要在返回它之前对对象执行一些操作,那么必须使用第一个对象。 垃圾收集方面没有区别。

1

如果使用反射来检查这个生成的代码:

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 
} 

显然编译器不能优化掉的调试版本额外的变量,如果你要检查它在调试。

因此,如果您想为调试目的而保留额外的变量,那么它很好 - 它对发布版本没有任何影响。

+0

但是,当您调用GetStream时,优化程序不会将它内联到发布版本中,因此它看起来像该方法甚至不存在。至少这种情况在使用这种帮助器方法查看堆栈跟踪器时经常发生。 –

+0

@JanneMatikainen JIT编译器可能会这样做,但当然C#编译器不会这样做。 –

1

我相信得到的优化JIT代码将是相同的。

GC的行为绝对没有影响,因为对象的生命周期将由使用返回值的人来决定(您可能正在考虑在函数结束之前不再使用值时的情况,在这里显然不是这样 - s在方法执行结束时返回)。

非优化(调试)构建中唯一明显的区别是您将能够看到s变量的值。