Ecco un esempio in cui i flag sono utili.
Ho un pezzo di codice che genera password (usando un generatore di numeri pseudocasuali crittograficamente sicuro). Il chiamante del metodo sceglie se la password deve contenere o meno lettere maiuscole, minuscole, cifre, simboli di base, simboli estesi, simboli greci, cirillici e unicode.
Con i flag, chiamare questo metodo è semplice:
var password = this.PasswordGenerator.Generate(
CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);
e può anche essere semplificato per:
var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);
Senza flag, quale sarebbe la firma del metodo?
public byte[] Generate(
bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols,
bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);
chiamato così:
// Very readable, isn't it?
// Tell me just by looking at this code what symbols do I want to be included?
var password = this.PasswordGenerator.Generate(
true, true, true, false, false, false, false, false);
Come notato nei commenti, un altro approccio sarebbe quello di utilizzare una raccolta:
var password = this.PasswordGenerator.Generate(
new []
{
CharacterSet.Digits,
CharacterSet.LowercaseLetters,
CharacterSet.UppercaseLetters,
});
Questo è molto più leggibile rispetto all'insieme di true
e false
, ma presenta ancora due svantaggi:
Il principale svantaggio è che per consentire valori combinati, come CharacterSet.LettersAndDigits
se stessi scrivendo qualcosa di simile nel Generate()
metodo:
if (set.Contains(CharacterSet.LowercaseLetters) ||
set.Contains(CharacterSet.Letters) ||
set.Contains(CharacterSet.LettersAndDigits) ||
set.Contains(CharacterSet.Default) ||
set.Contains(CharacterSet.All))
{
// The password should contain lowercase letters.
}
possibilmente riscritto in questo modo:
var lowercaseGroups = new []
{
CharacterSet.LowercaseLetters,
CharacterSet.Letters,
CharacterSet.LettersAndDigits,
CharacterSet.Default,
CharacterSet.All,
};
if (lowercaseGroups.Any(s => set.Contains(s)))
{
// The password should contain lowercase letters.
}
Confronta questo con quello che hai usando le bandiere:
if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters)
{
// The password should contain lowercase letters.
}
Il secondo, piccolo inconveniente è che non è chiaro come si comporterebbe il metodo se chiamato in questo modo:
var password = this.PasswordGenerator.Generate(
new []
{
CharacterSet.Digits,
CharacterSet.LettersAndDigits, // So digits are requested two times.
});