. Удаляет ли StreamWriter базовый поток?
StreamWriter.Close() говорит, что он также закрывает основной поток StreamWriter. Как насчет StreamWriter.Dispose? Dispose также удаляет и / или закрывает основной поток
7 ответов
StreamWriter.Close() просто вызывает StreamWriter.Dispose() под капотом, поэтому они делают то же самое. StreamWriter.Dispose() закрывает основной поток.
Отражатель - твой друг для подобных вопросов:)
Некоторые люди скажут, просто не утилизируйте поток, это действительно плохая идея, потому что, когда потоковый писатель выходит из области видимости, GarbageCollection может забрать его в любое время и добавить его, таким образом закрывая дескриптор потока, но создавая класс-потомок, который переопределяет это поведение StreamWriter легко, вот код:
/// <summary>
/// Encapsulates a stream writer which does not close the underlying stream.
/// </summary>
public class NoCloseStreamWriter : StreamWriter
{
/// <summary>
/// Creates a new stream writer object.
/// </summary>
/// <param name="stream">The underlying stream to write to.</param>
/// <param name="encoding">The encoding for the stream.</param>
public NoCloseStreamWriter(Stream stream, Encoding encoding)
: base(stream, encoding)
{
}
/// <summary>
/// Creates a new stream writer object using default encoding.
/// </summary>
/// <param name="stream">The underlying stream to write to.</param>
/// <param name="encoding">The encoding for the stream.</param>
public NoCloseStreamWriter(Stream stream)
: base(stream)
{
}
/// <summary>
/// Disposes of the stream writer.
/// </summary>
/// <param name="disposing">True to dispose managed objects.</param>
protected override void Dispose(bool disposeManaged)
{
// Dispose the stream writer but pass false to the dispose
// method to stop it from closing the underlying stream
base.Dispose(false);
}
}
Если вы посмотрите в Reflector / ILSpy, то обнаружите, что закрытие базового потока фактически выполняется в Dispose(true), а когда вызывается close, он просто вызывает Dispose, который вызывает Dispose(True), из кода не должно быть никаких других побочные эффекты, поэтому класс выше работает хорошо.
Возможно, вы захотите добавить все конструкторы, я просто добавил 2 здесь для простоты.
От StreamWriter.Close()
public override void Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
Из TextWriter.Dispose() (который наследует StreamWriter)
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
Таким образом, они идентичны.
Чтобы процитировать цитаты из Руководства по проектированию рамок от Квалины и Абрамса в разделе о шаблоне утилизации:
РАССМОТРЕТЬ метод предоставления
Close()
, в добавок кDispose()
, если близко - стандартная терминология в области.
Очевидно, что Microsoft следует своим собственным правилам, и при условии, что это почти всегда безопасная ставка для библиотеки базовых классов.NET.
Ответ прост и приведен выше: да, удаление потока закрывает любой основной поток. Вот пример:
public static string PrettyPrintXML_bug(XDocument document)
{
string Result = "";
using (MemoryStream mStream = new MemoryStream())
{
using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
{
writer.Formatting = Formatting.Indented; // <<--- this does the trick
// Write the XML into a formatting XmlTextWriter
document.WriteTo(writer);
// change the memory stream from write to read
writer.Flush();
mStream.Flush();
} // <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- this also "closes" mStream
mStream.Position = 0;//rewind <-- <-- <-- "cannot Read/Write/Seek"
// Read MemoryStream contents into a StreamReader.
using (StreamReader sReader = new StreamReader(mStream)) // <-- <-- Exception: Cannot access a closed stream
{
// Extract the text from the StreamReader.
Result = sReader.ReadToEnd();
}
}
return Result;
}
и вот решение, где вы должны отложить Dispose там, где базовый MemoryStream больше не нужен:
public static string PrettyPrintXML(XDocument document)
{
string Result = "";
using (MemoryStream mStream = new MemoryStream())
{
using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
{
writer.Formatting = Formatting.Indented; // <<--- this does the trick
// Write the XML into a formatting XmlTextWriter
document.WriteTo(writer);
// change the memory stream from write to read
writer.Flush();
writer.Close();
mStream.Flush();
mStream.Position = 0;//rewind
// Read MemoryStream contents into a StreamReader.
using (StreamReader sReader = new StreamReader(mStream))
{
// Extract the text from the StreamReader.
Result = sReader.ReadToEnd();
}
}// <-- here the writer may be Disposed
}
return Result;
}
Глядя на эти примеры, я не понимаю, почему закрытие базового потока является функцией.
Я просто любил поделиться этим.
Метод Dispose StreamWriter также закрывает базовый поток. Вы можете проверить это в справочном источнике здесь. Одна вещь, которую вы можете сделать, это использовать другой конструктор, который явно указывает, следует ли закрыть или оставить поток открытым. Проверьте аргумент leaveOpen:
public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen) : base(null)
Если вы планируете оставить его открытым, то рекомендуется передать флаг, установленный в «true», но затем удалить сам модуль записи потока, чтобы он не сохранял ссылку на поток и потенциально мог удалять другие ресурсы (хотя не похоже, что есть какие-либо ресурсы, кроме потока).