web-dev-qa-db-ja.com

ステートメントFileStreamおよび/またはStreamReaderを使用して-Visual Studio 2012の警告

新しいVisual Studio 2012は、私がいつも使っている一般的なコードの組み合わせについて不満を言っています。私はそれがやり過ぎのように見えることを知っていますが、「念のため」に私のコードで次のことをしました。

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (var sr = new StreamReader(fs))
    {
        // Code here
    }
}

Visual Studioは、fsを複数回破棄していることを「警告」しています。だから私の質問はこれです、これを書く適切な方法は次のようになりますか?

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    var sr = new StreamReader(fs);
    // do stuff here
}

または、このようにする必要があります(または言及されていない他のバリアント)。

var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

using (var sr = new StreamReader(fs))
{
    // Code here
}

StackOverflowでいくつかの質問を検索しましたが、この組み合わせのベストプラクティスに直接対応するものは見つかりませんでした。

ありがとうございました!

38
JHubbard80

以下は、 Microsoftが推奨する の方法です。長くてかさばりますが、安全です。

FileStream fs = null;
try
{
    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    using (TextReader tr= new StreamReader(fs))
    {
        fs = null;
        // Code here
    }
}
finally
{
    if (fs != null)
        fs.Dispose();
}

このメソッドは、例外がスローされる可能性があるにもかかわらず、すべてが破棄されることを常に保証します。たとえば、StreamReaderコンストラクターが例外をスローした場合、FileStreamは適切に破棄されます。

39
Dan

Visual Studioは、fsを複数回破棄していることを「警告」しています。

あなたはそうですが、それで結構です。 IDisposable.Dispose のドキュメントは次のとおりです。

オブジェクトのDisposeメソッドが複数回呼び出された場合、オブジェクトは最初の呼び出し以降のすべての呼び出しを無視する必要があります。オブジェクトは、Disposeメソッドが複数回呼び出された場合、例外をスローしてはなりません。

それに基づいて、警告は偽であり、私の選択はコードをそのままにして警告を抑制することです。

16
user743382

Danの答えはStreamWriterでのみ機能するように見えるため、これが最も受け入れられる答えであると考えています。 (Danの答えは、まだStreamReaderで破棄された2回の警告を与えます-Daniel Hilgarthと悪化したエキスパートが述べているように、StreamReaderはファイルストリームを破棄します)

using (TextReader tr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
    string line;
    while ((line = tr.ReadLine()) != null)
    {
        // Do work here
    }
}

これは、Daniel Hilgarthの答えに非常に似ており、StreamReaderがFileStreamでdisposeを呼び出すことが明確になったため、StreamReaderのUsingステートメントを介してdisposeを呼び出すように変更されました(他のすべての投稿、ドキュメントを参照)

更新:

この投稿を見つけました。それが価値があるもののために。 streamreaderを破棄するとストリームが閉じますか?

6
JHubbard80

はい、正しい方法は最初の代替手段を使用することです。

using (FileStream fs = new FileStream(filePath, FileMode.Open,
                                      FileAccess.Read, FileShare.ReadWrite)) 
{ 
    TextReader tr = new StreamReader(fs); 
    // do stuff here 
} 

その理由は次のとおりです。
StreamReaderを破棄すると、FileStreamのみが破棄されるため、実際に破棄する必要があるのはこれだけです。

2番目のオプション(内部の「使用」)は、FileStreamのコンストラクター内に例外があった場合にStreamReaderを破棄しないため、解決策ではありません。

2
Daniel Hilgarth

これは、StreamReaderの使用方法によって、ストリームが破棄されるときにストリームが破棄されるためです。したがって、ストリームも破棄すると、2回破棄されます。これはStreamReaderの欠陥だと考える人もいますが、それでもなお存在します。 VS 2012(.NET 4.5)では、StreamReaderに、新しいコンストラクターを使用して、ストリームを破棄しないオプションがあります。 http://msdn.Microsoft.com/en-us/library/gg712952

1

2つのソリューション:

[〜#〜] a [〜#〜])ReflectorまたはDocumentationを信頼し、_*Reader_および_*Writer_が基礎となる_*Stream_を閉じることを知っています。ただし、警告:スローされた例外の場合は機能しません。したがって、推奨される方法ではありません。

_using (TextReader tr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
    // Code here
}
_

[〜#〜] b [〜#〜])ドキュメントの状態として警告を無視します_The object must not throw an exception if its Dispose method is called multiple times._常にusingを使用することをお勧めします。 、スローされた例外の場合に安全:

_[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
internal void myMethod()
{
    [...]
    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (TextReader tr = new StreamReader(fs))
    {
        // Code here
    }
}
_
1
Cœur

この(完全に正当な!)質問が生成されたすべてのナンセンスを考えると、これは私の好みです:

FileStream fs = null;
TextReader tr= null;
try
{
    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    tr= new StreamReader(fs);
    // Code here
}
finally
{
    if (tr != null)
        tr.Dispose();
    if (fs != null)
        fs.Dispose();
}

以下のリンクは、完全に正当な構文を示しています。 IMO、この「使用する」構文は、ネストされた「使用する」よりもはるかに望ましいです。しかし、私は認めます-それは元の質問を解決しませんnot

私見では...

0
paulsm4