Существует ли более эффективная детерминированная схема удаления, чем вложенные "использование"?
В С#, если я хочу детерминистически очистить не управляемые ресурсы, я могу использовать ключевое слово "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.
}
}
}
В С++ я привык использовать деструкторы для этого:
{
FileStream fs("c:\file.txt", FileMode.Open);
BufferedStream bs(fs);
StreamReader sr(bs);
// use sr, and have everything cleaned up when done.
}
Есть ли лучший способ в С# для этого? Или я застрял с несколькими уровнями гнездования?
Ответы
Ответ 1
Вам не нужно вставлять несколько приемов:
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
}
Ответ 2
Вы можете использовать операторы сложения перед открытием таких скобок:
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
Ответ 3
Вы можете использовать этот синтаксис, чтобы свести к минимуму все:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
}
Это один из тех редких случаев, когда не использовать {} для всех блоков имеет смысл ИМХО.
Ответ 4
Вместо того, чтобы вставлять операторы, вы можете просто выписать вызовы .Dispose вручную, но в какой-то момент вы наверняка пропустите один из них.
Либо запустите FxCop, либо что-то еще, чтобы убедиться, что все экземпляры типа экземпляра IDisposable имеют вызов .Dispose() или имеют дело с вложением.
Ответ 5
Я уже реализовал решения, такие как Майкл Медоуз, но его код StreamWrapper
не учитывает, если методы Dispose()
, вызываемые на переменные-члены throw исключение по той или иной причине, последующие 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);
}
}
Ответ 6
вы можете опустить фигурные скобки, например:
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.
}
или используйте обычный метод try finally:
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
}
Ответ 7
Это делает намного больше net plus в строках кода, но ощутимым коэффициентом удобочитаемости:
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 может быть реорганизован как более общий и многоразовый.
Ответ 8
Следует отметить, что в целом при создании потока, основанного на другом потоке, новый поток закрывает тот, который передается. Таким образом, чтобы еще больше уменьшить ваш пример:
using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open))))
{
// all three get disposed when you're done
}
Ответ 9
для этого примера предположим, что у вас есть:
файл с именем 1.xml под c:\
текстовое поле с именем textBox1 с установленными значениями многострочных свойств.
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();
Ответ 10
Оператор using - синтаксический сахар, который преобразуется в:
try
{
obj declaration
...
}
finally
{
obj.Dispose();
}
Вы можете явно вызвать Dispose на своих объектах, но это будет не так безопасно, так как если один из них выдает исключение, ресурсы не будут правильно освобождены.