When you need to pass multiple options into a method, normally you would add a bool flag for each parameter, like:
DoStuff(bool prettyPrint, bool useEnumStrings)
Code language: C# (cs)
Not only is using bool flags a bit of a code smell, but when this list of parameters gets too big, you’ll probably want to refactor by moving the bool flags into an options class, like:
public class Options
{
public bool PrettyPrint {get;set;}
public bool UseEnumStrings {get;set;}
public bool IgnoreNulls {get;set;}
}
//caller
new Options() { PrettyPrint=true, UseEnumStrings=true };
Code language: C# (cs)
This is OK, but it’s pretty verbose. The caller has to new up an Options object and set all the flags it wants turned on.
There’s a simpler approach: enum flags.
With enum flags, you accept a single enum parameter, and the caller passes in all the options they want by bitwise ORing them together, like:
DoStuff(JsonOptions options)
//caller
DoStuff(PrettyPrint | JsonOptions.UseEnumStrings)
Code language: C# (cs)
In this article I’ll show how to create and use enum flags.
1 – Create enum with Flags attribute
There are two things to know to set this up properly:
- Add the [Flags] attribute to the enum.
- Set the values to powers of 2.
[Flags]
public enum JsonOptions
{
None = 0,
PrettyPrint = 1,
UseEnumStrings = 2,
IgnoreNulls = 4,
CaseInsensitive = 8
}
Code language: C# (cs)
2 – Accept the enum as a parameter and check which options are set
I have the following class that builds JsonSerializerOptions objects to use with System.Text.Json. It accepts a single JsonOptions enum parameter and then creates the JsonSerializerOptions objects based on which options were passed in.
Use HasFlag() to check if an option is set.
public class JsonOptionsBuilder
{
private readonly JsonSerializerOptions NONE;
public JsonOptionsBuilder()
{
NONE = new JsonSerializerOptions();
}
public JsonSerializerOptions Build(JsonOptions jsonOptions)
{
if (jsonOptions == JsonOptions.None)
{
return NONE;
}
var jsonSerializerOptions = new JsonSerializerOptions()
{
IgnoreNullValues = jsonOptions.HasFlag(JsonOptions.IgnoreNulls),
WriteIndented = jsonOptions.HasFlag(JsonOptions.PrettyPrint),
PropertyNameCaseInsensitive = jsonOptions.HasFlag(JsonOptions.CaseInsensitive)
};
if (jsonOptions.HasFlag(JsonOptions.UseEnumStrings))
{
jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
}
return jsonSerializerOptions;
}
}
Code language: C# (cs)
3 – Pass in combos of the enum
To pass in combos of the enum, you need to bitwise OR them together (using the | operator).
In the following example, I am passing in options PrettyPrint and UseEnumStrings.
var people = new List<Person>()
{
new Person()
{
FirstName = "Daniel",
LastName = "Jackson",
Job = "Archaeologist",
PetPreference= PetPreference.Dogs
},
new Person()
{
FirstName = "Samantha",
LastName = "Carter",
Job = "Astrophysicist",
PetPreference= PetPreference.Cats
}
};
var jsonOptionsBuilder = new JsonOptionsBuilder();
var options = jsonOptionsBuilder.Build(JsonOptions.PrettyPrint | JsonOptions.UseEnumStrings);
var personJson = JsonSerializer.Serialize(people, options);
Console.WriteLine(personJson);
Code language: C# (cs)