На самом деле нет способа заставить этот код избегать предупреждений, потому что в данном конкретном случае анализ кода неправильный.
Правильный код - 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 его потока, который является правильным, но HtmlTextWriter не избавляется от своего внутреннего TextWriter (проверяется путем создания подкласса StringWriter и установки точки останова в переопределенной утилизации) , Это немного сбивает с толку, поскольку HtmlTextWriter является производным от TextWriter, а StringWriter также является производным от TextWriter (в отличие от StreamWriter и его Stream, являющихся двумя совершенно разными классами), так почему HtmlTextWriter нужен InnerWriter?… Но в любом случае, именно так он работает .
Кроме того, в документации говорится, что не следует подавлять это предупреждение, поскольку «Даже если известно, что Dispose для объекта можно безопасно вызывать несколько раз, реализация может измениться в будущем». Однако в этом случае Dispose будет not вызывается несколько раз, поэтому предупреждение можно безопасно подавить.
Но не верьте мне на слово! Вот доказательство:
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);
}
}
}