5

我正在使用 .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;
}
4

3 回答 3

1

修改你的 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 文章中示例的修改版本,但专门适用于您的使用。

于 2013-09-17T18:50:08.187 回答
1

实际上没有办法让这段代码避免警告,因为在这种特殊情况下,代码分析是错误的。

正确的代码是 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 并在 override 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);
        }
    }

}
于 2014-12-05T23:04:04.190 回答
0

因为 StringWriter 是一次性的,你可以用另一个使用来包装你的内部作家。

using (StringWriter stringWriter = new StringWriter())
{
    using (var writer = new HtmlTextWriter(stringWriter))
    {
         html = stringWriter.ToString();  
    }
}
return html;
于 2012-01-10T22:36:33.010 回答