2011-08-31 18 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

我喜欢你在复制粘贴时甚至不打扰重命名变量的事实。您的代码无法编译 –