Here's an example when flags are useful.
I have a piece of code which generates passwords (using a cryptographically secure pseudorandom number generator). The caller of the method chooses whether or not the password should contain capital letters, small letters, digits, basic symbols, extended symbols, Greek symbols, Cyrillic ones and unicode.
With flags, calling this method is easy:
var password = this.PasswordGenerator.Generate(
CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);
and it can even be simplified to:
var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);
Without flags, what would be the method signature?
public byte[] Generate(
bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols,
bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);
called like this:
// 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);
As noted in the comments, another approach would be to use a collection:
var password = this.PasswordGenerator.Generate(
new []
{
CharacterSet.Digits,
CharacterSet.LowercaseLetters,
CharacterSet.UppercaseLetters,
});
This is much more readable compared to the set of true
and false
, but still has two drawbacks:
The major drawback is that in order to allow combined values, like CharacterSet.LettersAndDigits
you would be writing something like that in Generate()
method:
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.
}
possibly rewritten like this:
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.
}
Compare this with what you have by using flags:
if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters)
{
// The password should contain lowercase letters.
}
The second, very minor drawback is that it's not clear how would the method behave if called like this:
var password = this.PasswordGenerator.Generate(
new []
{
CharacterSet.Digits,
CharacterSet.LettersAndDigits, // So digits are requested two times.
});
newItem = true
then some lines belowif (newItem ) then