web-dev-qa-db-ja.com

streamreaderを破棄すると、ストリームが閉じられますか?

メソッドにストリームを送信して書き込みを行い、それらのメソッドではバイナリリーダー/ wrtierを使用しています。リーダー/ライターがusingによって破棄された場合、または参照されていない場合、ストリームも閉じられますか??

BinaryReader/Writerを送信しますが、StreamReaderも使用します(たぶんそれを回避する必要があります。GetLineとReadLineにのみ使用しています)。ライター/リーダーが閉じられるたびにストリームを閉じる場合、これは非常に面倒です。

155
Nefzen

はい、StreamReaderStreamWriterBinaryReader、およびBinaryWriterはすべて、Disposeを呼び出すときに、基になるストリームを閉じたり破棄したりします。 do n'tリーダー/ライターがガベージコレクトされている場合はストリームを破棄します-リーダー/ライターは常にusingステートメントで破棄する必要があります。 (実際、これらのクラスにはファイナライザーはありませんし、持っているべきでもありません。)

個人的には、ストリームのusingステートメントも使用することを好みます。中括弧なしでusingステートメントをきれいにネストできます。

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

ストリームのusingステートメントは多少冗長ですが(StreamReaderコンストラクターが例外をスローしない限り)、StreamReaderと後日直接ストリームを使用するだけで、適切な廃棄セマンティクスが既に得られます。

192
Jon Skeet

これは古いものですが、今日は似たようなことをしたかったため、状況が変わったことがわかりました。 .net 4.5以降、leaveOpen引数があります。

public StreamReader( Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen )

唯一の問題は、他のパラメーターに何を設定するかが完全に明らかではないことです。ヘルプがあります:

FrommsdnページStreamReaderコンストラクター(ストリーム)の場合:

このコンストラクターは、エンコードをUTF8Encodingに初期化し、streamパラメーターを使用してBaseStreamプロパティを初期化し、内部バッファーサイズを1024バイトに初期化します。

ソースコードで判断されるdetectEncodingFromByteOrderMarkstrueのままです

public StreamReader(Stream stream)
        : this(stream, true) {
}

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
        : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) {
}

これらのデフォルトのいくつかが公開されている場合、または引数がオプションであるため、必要なものを指定することができればいいでしょう。

41
acarlon

はい、そうです。 Reflectorで実装を確認することでこれを確認できます。

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {    
            this.stream = null;    
            this.encoding = null;
            this.decoder = null;
            this.byteBuffer = null;
            this.charBuffer = null;
            this.charPos = 0;
            this.charLen = 0;
            base.Dispose(disposing);
        }
    }
}
29
Brian Rasmussen

6年遅れですが、これは誰かを助けるかもしれません。

StreamReaderは、破棄された接続を閉じます。ただし、StreamReader/StreamWriterで「(stream stream = ...){...}」を使用すると、Streamが2回破棄される可能性があります。(1)StreamReaderオブジェクトが破棄されるとき(2)およびブロックを使用するストリーム閉じます。これにより、VSのコード分析の実行時にCA2202警告が発生します。

CA2202 ページから直接取得した別のソリューションは、try/finallyブロックを使用することです。正しくセットアップすると、接続は一度だけ閉じられます。

CA2202 の下部近くで、Microsoftは次の使用を推奨しています。

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    if(stream != null)
        stream.Dispose();
}

の代わりに...

// Generates a CA2202 warning
using (Stream stream = new FileStream("file.txt", FileMode.Open))
using (XmlReader reader = new XmlReader (stream))
{
    // Use the reader object...
}
13
Sunsetquest

はい。 Dispose()onおよびIDisposable( "using"を実行)を呼び出すと、オブジェクトはすべてのリソースをクリーンアップする必要があります。これには、ファイル記述子をフラッシュおよびクローズするストリームが含まれます。

あなたの場合、他のメソッドに渡す場合は、それらのメソッドがusingブロックで読み取り/書き込みを行わないようにする必要があります。

2
Joe M

必要に応じてこれを修正する簡単な方法は、StreamWriterクラスのDisposeメソッドをオーバーライドすることです。それを行う方法のコードについては、私の投稿を参照してください:

StreamWriterを破棄すると、基になるストリームが閉じられますか?

1