2013-06-28 47 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變量的值。