2011-11-11 15 views
25

Recentemente ho attivato regole aggiuntive per l'analisi del codice. Con mia sorpresa ho visto una violazione in un luogo che consideravo sempre come la migliore pratica. Se ho due monouso annidati sto mettendo due dichiarazioni utilizzando in questo modo:Nidificato utilizzando istruzioni e codice Microsoft Analisi

using (StringReader strReader = new StringReader(xmlString)) 
    using (XmlReader xmlReader = XmlReader.Create(strReader)) 
    { 
     result.ReadXml(xmlReader); 
    } 

Ciò corrisponde anche alla Q alta nominale & Un Nested using statements in C#

La violazione ottengo stati seguenti:

Warning 18 CA2202 : Microsoft.Usage : Object 'strReader' can be disposed more 
than once in method '????'. To avoid generating a System.ObjectDisposedException 
you should not call Dispose more than one time on an object.: Lines: ?? 

Quello che ho fatto è stato un tentativo intuitivo ed errore, pensando che la chiusura del flusso esterno probabilmente disporrà anche quella interna che ho risolto velocemente il mio codice in questo modo:

using (XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString))) 
    { 
     result.ReadXml(xmlReader); 
    } 

Hura! L'avviso è sparito. Ma, tada! Il nuovo si è verificato:

Warning 18 CA2000 : Microsoft.Reliability : In method '????????', object 
'new StringReader(xmlString)' is not disposed along all exception paths. Call 
System.IDisposable.Dispose on object 'new StringReader(xmlString)' before all 
references to it are out of scope. 

poi ho trovato una brutta soluzione:

{ 
     StringReader strReader = null; 
     try 
     { 
      strReader = new StringReader(xmlString); 
      using (XmlReader xmlReader = XmlReader.Create(strReader)) 
      { 
       strReader = null; 
       result.ReadXml(xmlReader); 
      } 
     } 
     finally 
     { 
      if (strReader != null) strReader.Dispose(); 
     } 
    } 

Come ultimo passaggio (come ogni buon programmatore) Ho guardato in pagina di aiuto per CA2202 e con mia sorpresa esattamente la mia ultima soluzione UGLY è stata proposta per risolvere il problema?

Dopo aver provato {} finalmente usando il codice clutter molto! Per me l'nidificazione è molto più leggibile.

Domanda: C'è un modo migliore di fare le cose? Sto cercando una soluzione che sia intuitivamente comprensibile. Tutti quelli che vedranno quest'ultimo frammento saranno curiosi di ciò che sta accadendo.

Grazie in anticipo per le vostre risposte.

+0

Domande come nel tuo P.S. probabilmente appartengono a MetaStackoverflow. In effetti, quella domanda potrebbe essere già stata posta e ha risposto lì. –

+0

proposito ho provato anche seguente codice 'utilizzando (StringReader strReader = new StringReader (xmlString)) usando (xmlReader xmlReader = XmlReader.Create (strReader)) { strReader = null; result.ReadXml (xmlReader); } ' porta per compilare errore Errore Non è possibile assegnare a 'strReader' perché è un 'utilizzando variabile' –

risposta

21

Il problema non è dovuto agli utilizzi nidificati. Stanno bene e generalmente raccomandato. Il problema qui è che XmlReader disporrà dello TextReader se si passa uno XmlReaderSettings con CloseInput == true, ma la regola CA2202 non è abbastanza intelligente da non far scendere il codice da quel ramo. Conserva i tuoi usi nidificati e sopprime la violazione CA2202 come falso positivo.

Se si vuole essere esplicito nel codice al fine di migliorare la sua leggibilità e/o manutenzione, utilizzare un XmlReaderSettings con CloseInput set per false, ma che è il valore di default, quindi non è strettamente necessario, e, per essere chiaro, non soddisferebbe la regola.

BTW, esistono scenari CA2202 simili per una varietà di tipi di flusso e lettore. Sfortunatamente, non sono tutti uguali a questo, quindi la migliore gestione dei casi può variare a seconda del tipo che causa il problema.

+0

' xmlReaderSettings.CloseInput = false' non soddisfa la regola. La soppressione sembra essere l'unico modo corretto per gestire questo problema. Sembra generalmente una buona idea tollerare il doppio smaltimento nelle implementazioni di 'Dispose', quindi alcuni utenti come' XmlReader' potrebbero licenziarti in silenzio e se qualcuno avvolge la tua classe in un'istruzione 'using' ne fa BOOM! Grazie per la grande spiegazione. Accettato! –

+3

Non stavo suggerendo che l'impostazione di CloseInput su false avrebbe soddisfatto la regola, ma piuttosto che si potrebbe voler essere espliciti nel codice al fine di migliorarne la leggibilità e/o la manutenibilità. Per quanto riguarda la tolleranza per lo smaltimento multiplo, esiste una linea guida di progettazione .NET per questo, anche se non esiste una regola FxCop corrispondente. –

0

Recentemente ho avuto un problema simile, ma poiché stavo usando un serializzatore ho dovuto adattarlo perché non ero in grado di impostare lo stringWriter su null immediatamente. Questa soluzione alternativa evita tutti gli avvisi della CA:

StringWriter stringWriter = null; 
XmlWriter xmlWriter = null; 
string serializedValue = null; 

try 
{ 
    XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); 
    stringWriter = new StringWriter(); 

    xmlWriter = XmlWriter.Create(stringWriter); 
    xmlserializer.Serialize(xmlWriter, value); 
    xmlWriter.Flush(); 
    serializedValue = stringWriter.ToString(); 
} 
finally 
{ 
    if (xmlWriter != null) //Both objects need disposed 
    { 
     xmlWriter.Dispose(); //stringWriter will dispose automatically too 
    } 
    else if (stringWriter != null) //XmlWriter failed to create 
    { 
     stringWriter.Dispose(); //just dispose stringWriter 
    } 
}