簡體   English   中英

如何在沒有代碼分析警告的情況下一起使用StringWriter和HtmlWriter

[英]How to use StringWriter and HtmlWriter together without Code Analysis warnings

我正在使用.net並且需要獲取一些html文本,所以我想我會一起使用HtmlTextWriter和StringWriter來獲得格式正確的html。 但是,盡管我編寫代碼的方式不同,我仍然會收到靜態代碼分析器的警告(使用Microsoft All Rules)。 在下面的代碼示例中,我在注釋中顯示代碼分析器警告。 為了簡化代碼,我實際上並沒有對HtmlTextWriter進行任何調用(您將在每個函數中看到對該效果的注釋)。 如何正確編寫代碼以避免警告?

// CA2000 : Microsoft.Reliability : In method 'Default.Func1()', object 'stringWriter' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'stringWriter' before all references to it are out of scope.
public static string Func1()
{
    string html;
    StringWriter stringWriter;
    using (var writer = new HtmlTextWriter(stringWriter = new StringWriter()))
    {
        // You would do some stuff with the writer here, but not for this example.

        html = stringWriter.ToString();
    }
    return html;
}

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in method 'Default.Func2()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 45
public static string Func2()
{
    string html;
    StringWriter stringWriter = null;
    try
    {
        using (var writer = new HtmlTextWriter(stringWriter = new StringWriter()))
        {
            // You would do some stuff with the writer here, but not for this example.

            html = stringWriter.ToString();
        }
    }
    finally
    {
        if (stringWriter != null)
            stringWriter.Dispose();
    }
    return html;
}

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in
// method 'Default.Func3()'. To avoid generating a System.ObjectDisposedException 
// you should not call Dispose more than one time on an object.: Lines: 61
public static string Func3()
{
    string html;
    using (var stringWriter = new StringWriter())
    {
        using (var writer = new HtmlTextWriter(stringWriter))
        {
            // You would do some stuff with the writer here, but not for this example.

            html = stringWriter.ToString();
        }
    }
    return html;
}

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in 
// method 'Default.Func4()'. To avoid generating a System.ObjectDisposedException you 
// should not call Dispose more than one time on an object.: Lines: 77
public static string Func4()
{
    string html;
    using (StringWriter stringWriter = new StringWriter())
    {
        using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
        {
            // You would do some stuff with the writer here, but not for this example.

            html = stringWriter.ToString();
        }
    }
    return html;
}

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in 
// method 'Default.Func5()'. To avoid generating a System.ObjectDisposedException you 
// should not call Dispose more than one time on an object.: Lines: 100
public static string Func5()
{
    string html;
    StringWriter stringWriter = null;
    try
    {
        stringWriter = new StringWriter();
        using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter))
        {
            // You would do some stuff with the writer here, but not for this example.

            html = stringWriter.ToString();
        }
    }
    finally
    {
        if (stringWriter != null)
            stringWriter.Dispose();
    }
    return html;
}

將您的Func5修改為如下:

public static string Func5()
{
    string html;
    StringWriter stringWriter = null;
    try
    {
        stringWriter = new StringWriter();
        using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter))
        {
            stringWriter = null;

            // You would do some stuff with the writer here, but not for this example.

            html = htmlTextWriter.InnerWriter.ToString();
        }
    }
    finally
    {
        if (stringWriter != null)
            stringWriter.Dispose();
    }
    return html;
}

關鍵是將stringWriter變量設置為null(這不會影響HtmlTextWriter實例的InnerWriter),然后使用InnerWriter.ToString()來獲取HTML。

這實際上只是之前評論中引用的MSDN文章中的示例的修改版本,但專門適用於您的用法。

實際上沒有辦法讓這段代碼避免警告,因為在這種特殊情況下,代碼分析是錯誤的。

正確的代碼是Func3,添加了CodeAnalysis.SuppressMessage屬性:

// Code Analysis is incorrectly assuming that HtmlTextWriter.Dispose will dispose of the InnerWriter, but it actually does not.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static string Func3()
{
    string html;
    using (var stringWriter = new StringWriter())
    {
        using (var writer = new HtmlTextWriter(stringWriter))
        {
            // You would do some stuff with the writer here, but not for this example.

            // I prefer to use writer.InnerWriter as opposed to stringWriter for clarity.
            html = writer.InnerWriter.ToString();
        }
    }
    return html;
}

CA2202的文檔使用StreamWriter處理其Stream的示例,這是正確的,但HtmlTextWriter不會處置其內部TextWriter(可通過子類化StringWriter並在覆蓋Dispose中設置斷點來驗證)。 這有點令人困惑,因為HtmlTextWriter派生自TextWriter,而StringWriter也派生自TextWriter(而不是StreamWriter,而Stream是兩個完全不同的類),那么為什么HtmlTextWriter需要InnerWriter?...但無論如何,這就是它的工作原理。

此外,文檔說不要禁止此警告,因為“即使已知對象的Dispose可以多次安全地調用,實現可能會在將來發生更改。”但是,在這種情況下,Dispose 不會被多次調用,所以可以安全地抑制警告。

但是不要相信我的話! 這是證明:

using System;
using System.IO;
using System.Web.UI;

namespace WebApplication1
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            StreamWillBeDisposed();
            TextWriterWillNotBeDisposed();
        }

        public static void StreamWillBeDisposed()
        {
            Stream stream = new DebugMemoryStream();
            using (StreamWriter writer = new StreamWriter(stream))
            {
                // Use the writer object...
            }// Underlying Stream will be disposed here by the StreamWriter
        }

        public static void TextWriterWillNotBeDisposed()
        {
            TextWriter stringWriter = new DebugStringWriter();
            using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
            {
                // Use the writer object...
            }// Underlying TextWriter will NOT be disposed here by the HtmlTextWriter
        }
    }


    public class DebugMemoryStream : MemoryStream
    {
        protected override void Dispose(bool disposing)
        {
            // This Stream will be disposed when the StreamWriter is disposed
            System.Diagnostics.Debugger.Break();
            base.Dispose(disposing);
        }
    }

    public class DebugStringWriter : StringWriter
    {
        protected override void Dispose(bool disposing)
        {
            // This code will never see the light of day
            System.Diagnostics.Debugger.Break();
            base.Dispose(disposing);
        }
    }

}

因為StringWriter是Disposable,所以你可以用你的內部編寫器包裝你的內部編寫器。

using (StringWriter stringWriter = new StringWriter())
{
    using (var writer = new HtmlTextWriter(stringWriter))
    {
         html = stringWriter.ToString();  
    }
}
return html;

暫無
暫無

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

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