是否有比嵌套“使用”更好的确定性处置模式?

在C#中,如果我想确定性地清理非托管资源,我可以使用“using”关键字。 但是对于多个依赖对象,这最终会进一步嵌套:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) { using (BufferedStream bs = new BufferedStream(fs)) { using (StreamReader sr = new StreamReader(bs)) { // use sr, and have everything cleaned up when done. } } } 

在C ++中,我习惯于使用析构函数来执行此操作:

 { FileStream fs("c:\file.txt", FileMode.Open); BufferedStream bs(fs); StreamReader sr(bs); // use sr, and have everything cleaned up when done. } 

在C#中有更好的方法吗? 还是我坚持多层次的嵌套?

您不必嵌套多个使用:

 using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) using (BufferedStream bs = new BufferedStream(fs)) using (StreamReader sr = new StreamReader(bs)) { // all three get disposed when you're done } 

您可以在开头大括号之前将using语句放在一起,如下所示:

  using (StreamWriter w1 = File.CreateText("W1")) using (StreamWriter w2 = File.CreateText("W2")) { // code here } 

http://blogs.msdn.com/ericgu/archive/2004/08/05/209267.aspx

您可以使用此语法稍微压缩一下:

 using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) using (BufferedStream bs = new BufferedStream(fs)) using (StreamReader sr = new StreamReader(bs)) { } 

这是一个罕见的场合,其中不使用{}对所有块有意义恕我直言。

您可以手动写出.Dispose调用,而不是使用语句进行嵌套,但在某些时候您几乎肯定会错过。

运行FxCop或其他可确保所有IDisposable实现类型实例都具有.Dispose()调用或处理嵌套的其他内容。

我之前已经实现了像Michael Meadows之类的解决方案,但他的StreamWrapper代码没有考虑调用成员变量的Dispose()方法因某种原因而抛出exception,后续的Dispose() es将不会呼叫和资源可能会摇摆不定。 这个工作的更安全的方式是:

  var exceptions = new List(); try { this.sr.Dispose(); } catch (Exception ex) { exceptions.Add(ex); } try { this.bs.Dispose(); } catch (Exception ex) { exceptions.Add(ex); } try { this.fs.Dispose(); } catch (Exception ex) { exceptions.Add(ex); } if (exceptions.Count > 0) { throw new AggregateException(exceptions); } } 

你可以省略花括号,比如:

 using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) using (BufferedStream bs = new BufferedStream(fs)) using (StreamReader sr = new StreamReader(bs)) { // use sr, and have everything cleaned up when done. } 

或者使用常规尝试最终方法:

 FileStream fs = new FileStream("c:\file.txt", FileMode.Open); BufferedStream bs = new BufferedStream(fs); StreamReader sr = new StreamReader(bs); try { // use sr, and have everything cleaned up when done. }finally{ sr.Close(); // should be enough since you hand control to the reader } 

这样就可以在代码行中获得更大的网络,但在可读性方面取得了明显的好处:

 using (StreamWrapper wrapper = new StreamWrapper("c:\file.txt", FileMode.Open)) { // do stuff using wrapper.Reader } 

这里定义了StreamWrapper:

 private class StreamWrapper : IDisposable { private readonly FileStream fs; private readonly BufferedStream bs; private readonly StreamReader sr; public StreamWrapper(string fileName, FileMode mode) { fs = new FileStream(fileName, mode); bs = new BufferedStream(fs); sr = new StreamReader(bs); } public StreamReader Reader { get { return sr; } } public void Dispose() { sr.Dispose(); bs.Dispose(); fs.Dispose(); } } 

通过一些努力,StreamWrapper可以被重构为更通用和可重用。

应该注意的是,通常在基于另一个流创建流时,新流将关闭传入的流。因此,为了进一步减少您的示例:

 using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open)))) { // all three get disposed when you're done } 

对于这个例子,让我们假设你有:

c:\下名为1.xml的文件

一个名为textBox1的文本框,其多行属性设置为ON。

 const string fname = @"c:\1.xml"; StreamReader sr=new StreamReader(new BufferedStream(new FileStream(fname,FileMode.Open,FileAccess.Read,FileShare.Delete))); textBox1.Text = sr.ReadToEnd(); 

using语句是语法糖,可转换为:

  try { obj declaration ... } finally { obj.Dispose(); } 

您可以在对象上显式调用Dispose,但它不会那么安全,因为如果其中一个抛出exception,资源将无法正确释放。