2011-08-31 19 views
4

返回值考慮以下幾點:處置和.NET

 TextReader reader = new StreamReader(file); 
     XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 
     return (T)xmlSerializer.Deserialize(reader); 

而且

 using (TextReader reader = new StreamReader(file)) 
     { 
      XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 
      return (T)xmlSerializer.Deserialize(reader); 
     } 

將在後面的代碼實際上發生什麼? Dispose()會被調用嗎?

+2

是處置將被調用。 –

回答

1

當使用範圍結束時,using語句的資源將被放置。在你的情況下,當反序列化的結果已經被澆鑄到T

可以擴展你的代碼爲(大約)以下等價的:在該版本

TextReader reader = null; 
try{ 
    reader = new StreamReader(file); 
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 
    var obj = xmlSerializer.Deserialize(reader); 
    T returnVal = (T)obj; 
    return returnVal; 
} finally{ 
    reader.Dispose(); 
} 

它變得清晰使用最後一次閱讀器是在return語句之前。

如果你要返回讀者,你會遇到問題,因爲返回的對象將被丟棄,因此無法使用。

編輯: 上面的代碼中的IL是:

IL_0000: nop 
    IL_0001: ldnull 
    IL_0002: stloc.0 
    .try 
    { 
    IL_0003: nop 
    IL_0004: ldstr  "" 
    IL_0009: newobj  instance void [mscorlib]System.IO.StreamReader::.ctor(string) 
    IL_000e: stloc.0 
    IL_000f: ldtoken !!T 
    IL_0014: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
    IL_0019: newobj  instance void [System.Xml]System.Xml.Serialization.XmlSerializer::.ctor(class [mscorlib]System.Type) 
    IL_001e: stloc.1 
    IL_001f: ldloc.1 
    IL_0020: ldloc.0 
    IL_0021: callvirt instance object [System.Xml]System.Xml.Serialization.XmlSerializer::Deserialize(class [mscorlib]System.IO.TextReader) 
    IL_0026: stloc.2 
    IL_0027: ldloc.2 
    IL_0028: unbox.any !!T 
    IL_002d: stloc.3 
    IL_002e: ldloc.3 
    IL_002f: stloc.s CS$1$0000 
    IL_0031: leave.s IL_003d 
    } // end .try 
    finally 
    { 
    IL_0033: nop 
    IL_0034: ldloc.0 
    IL_0035: callvirt instance void [mscorlib]System.IO.TextReader::Dispose() 
    IL_003a: nop 
    IL_003b: nop 
    IL_003c: endfinally 
    } // end handler 
    IL_003d: nop 
    IL_003e: ldloc.s CS$1$0000 
    IL_0040: ret 
} // end of method 

要注意的事情是,CS $ 1 $ 0000是返回值正好是唯一ret指令前推到堆棧中。所以執行順序與C#代碼中的不同。此外,值得注意的是,CSl $ 1 $ 0000和leave.sinstrcutions存儲的返回值之一,其中一個榮耀的GOTO。 leave.s離開try並跳轉到標籤IL_003d,就在將返回值推入堆棧之前

+0

不''返回'離開範圍,沒有調用Dispose()? – kasperhj

+0

@lejon finally塊將永遠被執行。實際上,在觀察IL時,只有從方法的返回點。多重回報聲明和最終積木基本上是榮耀GOTOs –

+0

所以,Amby的回答更像是你提到的IL? – kasperhj

3

是的,Dispose將被調用。

+0

我會補充說,可能有一些小警告:http://stackoverflow.com/questions/3216046/does-the-c-finally-block-always-execute/3216078#3216078但這些都是非常特殊的情況,所以OP可以忽略它們。 – xanatos

4

是的,它會被調用。

using語句是語法糖:

try 
{ 
    // Do stuff 
    return; 
} 
finally 
{ 
    // Dispose 
} 

finally將調用甚至在return

所以你可以安全地使用它。

1

是的,這是如何在IL中轉換的。

TextReader reader; 
    T returnValue; 
    try{ 
     reader = new StreamReader(file)); 
     XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 
     var obj = xmlSerializer.Deserialize(reader); 
     returnVal = (T)obj; 
    } 
    finally{   
     reader.Dispose(); 
     return returnVal;    
    } 
+0

這與其他答案有所不同,儘管它最有意義的是最後完成了回報,正如我所期望的那樣。這是否確實如此,其他答案是否隱藏了這個事實? – kasperhj

+0

我喜歡你在複製粘貼時甚至不打擾重命名變量的事實。您的代碼無法編譯 –