簡體   English   中英

C#CA2000:使用FileStream / XmlTextReader在丟失范圍之前處置對象

[英]C# CA2000:Dispose objects before losing scope using FileStream/XmlTextReader

我有很多像這樣的代碼:

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而且我不禁想到我做錯了什么但是我沒有看到它。 我究竟做錯了什么?

嘆氣,筋疲力盡吧。 通過使用推薦的Create()方法避免所有這些:

 using (var reader = XmlReader.Create(@"C:\Temp\SNB-RSS.xml")) {
     //...
 }

由於沒有人提供解決此問題的解決方案,我正在編寫我的工作解決方案:

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。

我猜只是; 現在沒有時間進行全面分析。

假設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是出於各種各樣的原因,這是一件好事。 )。

這是一個眾所周知的問題

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

如果您使用的是StreamWriter而不是XmlTextReader(如上面的解決方案中所示),您可以通過相關的構造函數使用類似的方法; 例如

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

要么

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

從文檔中不清楚第一種形式的構造函數是否會覆蓋或附加到文件。

正如答案中所提到的,正確解決它的唯一方法是按照CA2202中的建議進行操作,並使用外部try-finally塊而不是外部使用塊。 在內部使用中,將外部IDisposable對象設置為null,以防止在內部使用完成后訪問它。

這是一個通用的包裝器,它“正確地”執行它,即在設計糟糕的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;
    });

相當笨重,你可能會說,這是更好地重復嘗試/套空/最后的圖案代替。 但是對於嵌套使用的重復模式,我寧願這樣做,也不是每次重復完整的事情。

只需使用'using'作為文件流

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

}

不要修改fs,也不要在花括號內部使用fs.close()。

也可以像在XmlTextReader上一樣在FileStream上使用using語句。

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

格茲,克里斯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM