2014-10-29 19 views
14

Uso l'analisi del codice statico nei nostri progetti per verificare la presenza di violazioni del codice. Una delle regole ampiamente utilizzate è CA2213, che controlla il corretto smaltimento dei campi usa e getta.Regola di analisi del codice CA2213 e proprietà auto-implementate

Ho notato che CA2213 non controlla lo smaltimento delle proprietà implementate automaticamente.

Inoltre CA2213 non controlla lo smaltimento di nessuno dei campi né delle proprietà autoattive se la classe eredita dalla classe che implementa IDisposable e non sovrascrive il metodo Dispose.

Esempio pratico:

public sealed class Good : IDisposable { 
    private Font font; 
    public Font Font { 
     get { return font; } 
     set { font = value; } 
    } 
    public Good() { font = new Font("Arial", 9); } 
    public void Dispose() { /* Do nothing */ }  // CA2213 
} 

public sealed class Bad : IDisposable { 
    public Font Font { get; set; } 
    public Bad() { Font = new Font("Arial", 9); } 
    public void Dispose() { /* Do nothing */ }  // No warning 
} 

Qualcun altro ha incontrato questo comportamento? È questo in base alla progettazione o al bug nella regola CA2213?

risposta

0

Gli strumenti di analisi statici sono sintonizzati per un buon compromesso tra la generazione di troppi falsi positivi (cioè problemi di emissione su un codice perfettamente preciso) e troppi falsi negativi (ovvero problemi reali mancanti nel codice).

Facciamo un semplice esempio:

// CA2213 detects an issue 
class OwnsTheField : IDisposable 
{ 
    private MemoryStream f = new MemoryStream(); 
    public void Dispose() {} 
} 

E 'chiaro che in questo caso un problema deve essere segnalato, e che è davvero il caso.

Ora, facciamo un po 'più complicate le cose:

// CA2213 does not detect 
class FieldIsInjected : IDisposable 
{ 
    private MemoryStream f; 
    public FieldIsInjected(MemoryStream p) 
    { 
     f = p; 
    } 
    public void Dispose() { } 
} 

In questo caso, non ci potrebbe essere un problema con lo smaltimento non f. Se p sia correttamente disposto dal chiamante, allora tutto funziona come previsto:

using (var p = new MemoryStream()) 
{ 
    using (var x = FieldIsInjected(p)) { /* ... */ } 
} // p is properly disposed 

Più spesso che no, non sarà documentata l'esatto comportamento (compresa la gestione di tutti i casi d'angolo), come la documentazione esaustiva sarebbe troppo costoso da mantenere nel tempo. Ad esempio, questa eccezione è esplicitamente menzionata in https://msdn.microsoft.com/en-us/library/ms182328.aspx

+0

Nel caso in cui si elenchino, Code Analysis richiede comunque di gestire 'f' in qualche modo, di solito eliminando manualmente e notando nella giustificazione che il campo iniettato non è di proprietà della classe corrente. Questa è una soluzione eccellente per me. Ciò che non è una buona soluzione non mostra affatto il problema dell'analisi del codice, semplicemente perché 'f' è un autoproperty o perché FieldIsInjected deriva da una classe IDisposable e non sovrascrive Dispose (bool) –

0

La regola è da .net framework 2 e auto properties are from C# 3, che è stata aggiunta alle specifiche della lingua dopo la creazione della regola. La regola è definita in termini di campi e non proprietà, quindi sembra che sia dovuto per un aggiornamento ma funziona come attualmente specificato.

This Question on disposing properties sembra mostrare che le proprietà che implementano IDisposable non sono coerenti nel framework.

4

Gli analizzatori di codice hanno limitazioni, quello presente in questo codice è che è necessario generare un avviso utilizzabile. Una che il programmatore può effettivamente seguire per correggere il suo codice. Un problema chiave con l'analizzatore di codice corrente è che non analizza il codice sorgente, funziona dall'assembly generato dal compilatore. Che è bello, funziona per qualsiasi linguaggio .NET. Ma nessuno piacerà questo avvertimento:

CA2213 campi monouso devono essere smaltiti
'Bad' contiene campo <Font>k__BackingField che è di tipo IDisposable: 'carattere'. Cambia il metodo Dispose in 'Bad' per chiamare Dispose o Close in questo campo.

Yikes, ovviamente non esiste questo campo nel programma. Per generare un messaggio migliore, l'analizzatore dovrebbe capire che il campo <Font>k__BackingField nei metadati è infatti associato alla proprietà Font auto-implementata. Non c'è nulla di disponibile nei metadati che rende questa connessione inequivocabile. Il campo porta solo l'attributo [CompilerGenerated] e il nome del campo generato automaticamente è un dettaglio di implementazione del compilatore. I compilatori di lingue diverse generano nomi diversi.

È il tipo di problema che richiede l'analisi del codice sorgente, non l'analisi IL come attualmente implementata. L'opportunità sta bussando alla porta, l'analisi del codice sorgente sarà molto più facile da implementare con Roslyn oggi disponibile. VS2015 è la prima versione VS che supporta l'analisi "Codice live". Non so ancora se cercherà presto gli errori di stile CA2213.

+0

Esiste una soluzione che può funzionare per VS2012? Come una regola StyleCop che si attiva su AutoProperties che ereditano da IDisposable? –

+0

Segnalo questa risposta per la quantità in quanto spiega la difficoltà del motore di analisi del codice rispetto all'analisi IL. La risposta sembra essere che per impostazione predefinita non è possibile coprire i problemi che io e Zvonko abbiamo delineato. Se in futuro trovo un metodo per creare una regola StyleCop per gestirlo, o passiamo a Roslyn e ho il tempo di aggiungere una regola personalizzata per l'analisi del codice, quindi mi assicurerò di aggiornare. –

+0

Sono d'accordo, la soluzione non è semplice. Per coprire il maggior numero possibile di casi durante l'analisi del codice sorgente (e per evitare che il codice errato vada al nostro VCS), combino diversi approcci: analisi del codice sorgente (StyleCop), analisi IL (FxCop), test unitari con riflessione (per forzare le regole su tipi specifici), codice di programma aggiuntivo (che viene eseguito solo in debug build o quando il debugger è collegato) e script PowerShell personalizzati. Ovviamente i check-in con gating sono abilitati e fanno tutto questo. – Zvonko

0

Il motore di analisi è perfettamente in grado di camminare tra la proprietà e il suo campo di appoggio. Semplicemente non ha la logica per farlo, e quindi manca un'opportunità per un avvertimento. Peggio ancora, emette uno false warning se una proprietà correttamente predisposta è di sola lettura.