在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#中有更好的方法吗?还是我坚持多层次的嵌套?
答案 0 :(得分:40)
您不必使用多个使用嵌套:
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
}
答案 1 :(得分:8)
您可以在开头括号之前将使用语句放在一起,如下所示:
using (StreamWriter w1 = File.CreateText("W1"))
using (StreamWriter w2 = File.CreateText("W2"))
{
// code here
}
答案 2 :(得分:3)
您可以使用此语法稍微压缩一下:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
}
这是一个罕见的场合,其中没有使用{}对所有块有意义恕我直言。
答案 3 :(得分:1)
您可以手动写出.Dispose调用,而不是使用语句进行嵌套,但在某些时候您几乎肯定会错过。
运行FxCop或其他可以确保所有IDisposable实现类型实例都有.Dispose()调用,或者处理嵌套的东西。
答案 4 :(得分:1)
我之前已经实现了Michael Meadows之类的解决方案,但是他的StreamWrapper
代码没有考虑调用成员变量的Dispose()
方法是否因某种原因而抛出异常或者另一个,随后的Dispose()
es将不被调用,资源可能会悬挂。这个工作的更安全的方式是:
var exceptions = new List<Exception>();
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);
}
}
答案 5 :(得分:0)
你可以省略大括号,例如:
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
}
答案 6 :(得分:0)
这使得代码行中的网络数量大得多,但可读性显着增加:
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可以被重构为更通用和可重用。
答案 7 :(得分:0)
应该注意的是,通常在根据另一个流创建流时,新流将关闭传入的流。因此,为了进一步减少您的示例:
using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open))))
{
// all three get disposed when you're done
}
答案 8 :(得分:0)
对于这个例子,我们假设你有:
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();
答案 9 :(得分:-1)
using语句是语法糖,转换为:
try
{
obj declaration
...
}
finally
{
obj.Dispose();
}
您可以在对象上显式调用Dispose,但它不会那么安全,因为如果其中一个抛出异常,资源将无法正常释放。