8

次のようなコードがたくさんあります。

FileStream fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open); 
using (XmlTextReader reader = new XmlTextReader(fs)) 
{ 
   /* Some other code */
}

これにより、次のコード分析警告が表示されます。

CA2000 : Microsoft.Reliability : In method 'SF_Tester.Run()', object 'fs' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'fs' before all references to it are out of scope.

提案に従って File.Open を using ステートメントに入れると、次のようになります。

CA2202 : Microsoft.Usage : Object 'fs' can be disposed more than once in method 'SF_Tester.Run()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 39

私はVS2010を使用していますが、何か間違ったことをしていると思わずにはいられませんが、それはわかりません。私は何を間違っていますか?

4

7 に答える 7

15

はあ、疲れるね。推奨される Create() メソッドを使用して、これらすべてを回避します。

 using (var reader = XmlReader.Create(@"C:\Temp\SNB-RSS.xml")) {
     //...
 }
于 2010-06-27T19:15:13.260 に答える
11

この問題を解決するソリューションをまだ誰も提供していないので、私はここに私の実用的なソリューションを書いています:

FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite,    FileShare.ReadWrite);
try
{
   using (var fileWriter = new StreamWriter(fs, encoding))
   {
       fs = null;
       fileWriter.Write(content);
    }
 }
 finally
 {
     if (fs != null)
         fs.Dispose();
 }

これにより、CA2000が削除されます。

于 2010-09-13T12:41:31.137 に答える
1

これは既知の問題です

http://connect.microsoft.com/VisualStudio/feedback/details/535118/ca2000-and-ca2202-offer-contradictory-warnings

XmlTextReaderではなくStreamWriterを使用している場合(上記のソリューションのように)、関連するコンストラクターを介して同様のメソッドを使用できます。例えば

var sw = new StreamWriter("filename.txt");

また

var sw = new StreamWriter("filename.txt", /*append to file = */ false );

コンストラクターの最初の形式がファイルを上書きするのか、ファイルに追加するのかは、ドキュメントからは明らかではありません。

于 2010-08-18T08:56:11.487 に答える
1

私は推測しているだけです。今は完全な分析を行う時間がありません。

コンストラクXmlTextReaderターが渡されたストリームの「所有権を取得」し、その意志を基になるストリームXmlTextReaderも破棄するとします。Disposeそれはあなたが見る行動を説明するでしょう。おそらくXmlTextReaderコンストラクターがスローする可能性があり、その場合、元の警告fsは理にかなっています。ただし、その仮説を考えると、このコードは

        var fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open);
        XmlTextReader reader = null;
        try
        {
            reader = new XmlTextReader(fs);
        }
        finally
        {
            if (reader== null)
            {
                fs.Dispose();
            }
        }
        if (reader != null)
        {
            using (reader)
            {
                /* Some other code */
            }
        }

正しいと思いますが、それでも偽の警告が表示されます。これは、静的分析ツールの限界を示す良い例のように思えます。

他の誰かが言ったように、ファイル名からリーダーを直接作成する別の API があります ( XmlReader.Create())。これは、このすべてを回避します (そして、驚くほどさまざまな理由で、適切に設計されたシナリオに焦点を当てた API がいかに優れているかを示しています)。

于 2010-06-27T19:15:22.017 に答える
0

ファイルストリームに「using」を使用するだけです

 using(FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
// some codes here

}

fs を変更したり、中括弧を使用して内部で fs.close() を使用したりしないでください。

于 2014-12-01T14:00:17.400 に答える
0

この回答で述べたように、それを正しく回避する唯一の方法は、CA2202 で推奨されているように実行し、外側の using ブロックの代わりに外側の try-finally ブロックを使用することです。内側の using 内で、外側の IDisposable オブジェクトを null に設定して、内側の using が終了するとアクセスされないようにします。

これは、「正しく」それを行う一般的なラッパーです。つまり、不適切に設計された XmlReader を回避します (おそらく、受信したストリームの所有権を取得するべきではありませんでしたか?それを行う正しい方法が何であるかはわかりません)。

免責事項:実際にはテストされていません

public static TResult SafeNestedUsing<TOuter, TInner, TResult>(Func<TOuter> createOuterDisposable, Func<TOuter, TInner> createInnerDisposable, Func<TInner, TResult> body)
        where TInner : IDisposable
        where TOuter : class, IDisposable
    {
        TOuter outer = null;
        try
        {
            outer = createOuterDisposable();
            using (var inner = createInnerDisposable(outer))
            {
                var result = body(inner);
                outer = null;
                return result;
            }
        }
        finally
        {
            if (null != outer)
            {
                outer.Dispose();
            }
        }
    }

使用例:

SafeNestedUsing<MemoryStream, XmlReader, XmlDocument>(
    ()          => new MemoryStream(array),
    (memStream) => XmlReader.Create(memStream, xmlReaderSettings),
    (xmlReader) =>
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlReader);
        return xmlDoc;
    });

これ非常に扱いにくいので、代わりに try/set null/finally パターンを繰り返す方がよいと主張するかもしれません。しかし、ネストされた usings の繰り返しパターンについては、毎回すべてを繰り返すよりも、この方法を使用したいと思います。

于 2013-01-03T01:05:18.993 に答える
-1

usingXmlTextReaderの場合と同様に、FileStream自体でもステートメントを使用します。

http://msdn.microsoft.com/en-us/library/system.io.filestream(VS.71).aspx

Grz、Kris。

于 2010-06-27T18:58:55.420 に答える