2011-08-20 7 views
6

Il MSDN documentation per l'attributo Flag dice che si dovrebbe:enumerazioni Flag senza potenza di due valori

definire costanti di enumerazione in potenze di due, vale a dire, 1, 2, 4, 8, e così via . Ciò significa che i singoli flag nelle costanti combinate di enumerazione non si sovrappongono.

... e naturalmente cerco sempre di ricordare di farlo. Tuttavia, nulla far rispettare questo e se si crea un'enumerazione il modo in cui 'base' come ...

[Flags] 
public enum BrokenEnum 
{ 
    None, 
    FirstOption, 
    SecondOption, 
    ThirdOption 
} 

... non si comporterà come previsto. Per combatterlo, sto cercando una specie di analisi del codice statico (come FxCop) che può avvisarmi quando esiste un enum simile a quello sopra nel mio codice. L'avvertimento più simile che ho trovato è stato 'CA1008: Enums should have zero value', che è anche utile per progettare correttamente l'enumerazione delle bandiere ma non è sufficiente.

Qual è il modo migliore per trovare enumerazioni di bandiere progettate in modo errato nel mio codice? Più la soluzione è automatizzata, meglio è.

risposta

2

Come dice Jacob, può essere utile avere miscele di bandiere ... ma forse potresti indicarlo in qualche modo in modo che il tuo rilevamento non dispiaccia.

Non dovrebbe essere troppo difficile scrivere un test di unità che attraversa ogni enum in un assieme decorata con [Flags] e controlla che c'è un valore per 0 (possibilmente assicurando si chiama None o Default) e che ogni altro valore definito (da Enum.GetValues()) è una potenza di due. Puoi verificarlo usando if ((x & (x - 1)) == 0).

Si potrebbe potenzialmente avere qualcosa come un attributo [Combination] per indicare valori che sono progettati per essere combinazioni ... potrebbero anche indicare quali nomi di flag sono destinati a essere combinazioni di, quindi è possibile controllare anche questo.

So che questo non è abbastanza buono come un controllo in fase di compilazione, ma supponendo che tu stia già facendo test regolarmente, è molto vicino.

+1

Suppongo che non avrei dovuto pensare "dentro la scatola" dell'analisi statica del codice. Un test unitario come questo dovrebbe essere abbastanza semplice e mi darà quasi lo stesso risultato finale. –

3

A volte si desidera avere un enumerazione di flag che rappresenta più opzioni; in casi come quello, non è un errore. Ecco un esempio comune:

[Flags] 
public enum FilePermissions 
{ 
    None = 0, 
    Read = 1, 
    Write = 2, 
    Execute = 4, 

    ReadWrite = 3, // Read | Write, 
    ReadWriteExecute = 7 // Read | Write | Execute 
} 

Forse a causa della necessità di sostenere i casi come questi, è per questo che un compilatore non causa un avvertimento o un errore.

+0

Sono in grado di vedere i motivi per cui il compilatore non lo fa (considerando anche la retrocompatibilità, la complessità ingiustificata, ecc.) Quindi sto bene che non si ottiene un avviso del compilatore. Ma sto ancora cercando un modo per essere avvertito. In casi come i vostri l'uso è valido, è possibile disabilitare l'ispezione con qualcosa come l'attributo 'SuppressMessage'. –

+0

Puoi anche avere bandiere più elaborate. Ad esempio '{Visualizza = 1, Modifica = 2, Azione = 4 | Visualizza | Alter} ': quindi per agire su un oggetto è necessario Visualizza e modifica; oltre al diritto stesso. –

3

Non l'ho mai provato, ma forse potresti scrivere una regola personalizzata per FxCop.

Controllare FxCop and Code Analysis: Writing Your Own Custom Rules.

+0

Grazie, sembra molto promettente.Potrei restare con la risposta di Jon Skeet solo perché penso che sarà più veloce a breve termine scrivere un test unitario invece di imparare come scrivere una regola FxCop personalizzata. –