2012-01-10 8 views
5

Sto usando .net e ho bisogno di ottenere del testo html, quindi ho pensato di utilizzare HtmlTextWriter e StringWriter per ottenere l'html ben formato. Ma nonostante tutti i diversi modi in cui scrivo il codice, ricevo comunque degli avvisi dall'analizzatore di codici statici (utilizzando Microsoft All Rules). Negli esempi di codice qui sotto, mostro l'avvertenza dell'analizzatore del codice in un commento. Per semplificare il codice, in realtà non faccio alcuna chiamata a HtmlTextWriter (vedrai un commento a tale effetto in ogni funzione). Come posso scrivere il codice correttamente per evitare gli avvertimenti?Come utilizzare StringWriter e HtmlWriter insieme senza avvisi di analisi del codice

// 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; 
} 
+0

un sacco di commenti interessanti su [CA2202] (http://msdn.microsoft.com/en-us/library/ms182334.aspx) su MSDN –

+1

Purtroppo nessuno dei commenti alla Il collegamento CA2202 in precedenza ha indirizzato l'avviso in questa particolare coppia di classi quando li ho provati. –

+0

In [un altro post] (http://stackoverflow.com/questions/3831676/ca2202-how-to-solve-this-case), Hans Peter scrive "Questi non sono esattamente bug reali, queste classi .NET sono resistenti a più chiamate Dispose(). " Con questo in mente sono tentato di fare il doppio utilizzo come Func3 o Func4 e sopprimere l'avviso CA2202. –

risposta

0

Perché StringWriter è Usa e getta puoi avvolgere il tuo scrittore interno con un altro utilizzando.

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

È praticamente uguale al suo 'Func3()' e 'Func4()'. –

+0

@JesseC.Slicer oops my bad, non ho visto func3 e 4 –

+0

Ho appena scaricato FXCop 10.0.30319.1 e ho scritto un po 'di test harness usando questo ed è tutto a posto, non vedo nessun problema. Ho un avvertimento su Mark wirht StrongName, IFormatProvider, MarkAssembliesWithNeutralResourcesLanguage ma nulla su disposizione. –

1

Modificare la Func5 essere i seguenti:

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; 
} 

La chiave è impostare la variabile StringWriter null (che non influisce sulla InnerWriter dell'istanza HtmlTextWriter) e quindi utilizzare l'InnerWriter. ToString() per ottenere l'HTML.

Questa è solo una versione modificata dell'esempio nell'articolo MSDN a cui si fa riferimento in un commento precedente ma applicato in modo specifico all'utilizzo.

1

Non c'è in realtà alcun modo per evitare che questo codice elimini gli avvisi perché in questo caso particolare, l'analisi del codice è errata.

Il codice corretto è Func3, aggiungendo un attributo 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; 
} 

La documentazione per CA2202 utilizza un esempio di uno StreamWriter smaltimento del suo flusso, che è corretto, ma HtmlTextWriter non cedere la sua TextWriter interno (verificabile per sottoclasse di StringWriter e impostazione di un punto di interruzione in Sovrascrittura Dispose). Questo è un po 'confuso, dal momento che HtmlTextWriter deriva da TextWriter, e StringWriter deriva anche da TextWriter (al contrario di StreamWriter e il suo Stream sono due classi completamente diverse) quindi perché HtmlTextWriter ha bisogno di un InnerWriter? ... ma comunque, funziona così .

Inoltre, la documentazione dice di non sopprimere questo avviso perché “Anche se Dispose per l'oggetto è noto per essere in sicurezza callable più volte, l'implementazione potrebbe cambiare in futuro.” Tuttavia, in questo caso Dispose non è viene chiamato più volte, quindi l'avviso può essere soppresso in modo sicuro.

Ma non credetemi! Ecco la prova:

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); 
     } 
    } 

} 
Problemi correlati