Introduction To Enums
Enums are user-defined data types. Inside they are integers and play a very important role in application development. They solve most of the problems and help us define the boundaries for allowed values.
Let us explore the number of ways to work with enum in C#.
Key Points
- Enums are part of the System namespace.
- They are by default non-nullable value types and behave like structs.
- The hierarchy is as follows, Objects → System.ValueType → System.Enum → (or enum)
Enums are of 2 types,
- Simple Enum Declaration
- Flag Enum Declaration
Simple Declaration
These are simple enum declarations, we create an enum and by default value gets assigned starting from 0 or we can explicitly assign numerical value to each enum value.
public enum SingleColor {
RED,
GREEN,
BLUE
}
Flag Enums Declaration
These are much more powerful than simple Enums and support multiple values assignment. Underneath, they work based on bits value and the numeric assignment for these values should not be a simple sequence. We will see this next. To use this we need to declare a flag attribute at the top of an enum.
[Flags]
public enum Colors {
RED = 1,
GREEN = 2,
BLUE = 4
}
Setting enum values
Simple Enum
Reading a simple enum is straightforward.
var selectedColor = SingleColor.BLUE;
Console.WriteLine(selectedColor); //BLUE
Flag Enum
Flag Enums contains multiple values and works on the bits data type. So, there are multiple ways to read flag Enums.
var selectedColors = Colors.BLUE | Colors.GREEN | Colors.RED;
Console.WriteLine(selectedColors); //RED, GREEN, BLUE
Extending enum properties
For extending, we can use Extension methods. Let us understand one example. We will use the extension method to check if color exists in Flag Enum.
public static bool IsSelectedColor(this Colors colors, Colors color) {
return colors.HasFlag(color);
}
var selectedColorBG = EnumsHandler.Colors.BLUE | EnumsHandler.Colors.GREEN;
Console.WriteLine("Is Blue Selected: " + selectedColorBG.IsSelectedColor(EnumsHandler.Colors.BLUE)); //True
Console.WriteLine("Is Red Selected: " + selectedColorBG.IsSelectedColor(EnumsHandler.Colors.RED)); //False
Enums in .NET Web API
In this example, we will check how enums work in Web API requests. What happens when we don’t validate and how we can validate it.
We are going to use the Colors enum used above. We will test with Flag enum. This code will also work for simple enum except that it will return only 1 value.
The controller's code is below,
[Route("api/[controller]")]
[ApiController]
public class ValuesController: ControllerBase {
[HttpPost]
public IActionResult Colors(EnumRequest request) {
return Ok(new {
result = "Selected Color is : " + request.ColorRequest
});
}
}
Without Validation
Now, we will create a request model without validation.
public class EnumRequest {
public EnumsHandler.Colors ColorRequest {
get;
set;
}
}
We will send the value 100, and the output will look like below. This case will return 100 because no enum uses 100 as an assignment. In the next section, we will look for ways to avoid such invalid requests.
Next, we can send valid values i.e. 1/2/4 or their combination since it is a flag enum. In this case, I will send 6 which returns 2 colors using 2+4 logic in simple words. Let’s see what the response is.
With Validation
Validating enums is easy, we have enum data type attribute available. This will restrict the use of values depending upon enum boundaries. It will return 400 Bad Request for Invalid requests and 200 as a convention when the value is valid.
using System.ComponentModel.DataAnnotations;
public class EnumRequest {
[EnumDataType(typeof(EnumsHandler.Colors))]
public EnumsHandler.Colors ColorRequest {
get;
set;
}
}
Now, we will try the above scenarios again,
Using 100 in request,
This time we will try using 7 as it will show all the colors, 1+2+4 adds up all the enum values and returns 7.
Nullable Enums
This is a very small topic. We can also null the enum values when our business requirement wants us to do that. This step is simple and straightforward. We will modify the above logic a little bit to replicate the null behavior.
Right now, if we send a null value it will return 400 Bad Request as Response.
Now, let us add a nullable operator in the request model. We can simply add “?” and it will work.
It is shorthand for Nullable<> operator.
[EnumDataType(typeof(EnumsHandler.Colors))]
public EnumsHandler.Colors ? ColorRequest {
get;
set;
}
Enum conversions in entity framework core
Enums are numbers internally. So should we explicitly convert them to string when saving them to our database? Or should we save the numbers and read them as enums from our application. This usage entirely depends on how we want to handle business use cases. There are various ways to handle this. In this example, I will show you how we can use value converters to save Enum as String in our database.
- We will download Microsoft.EntityFrameworkCore Nuget Package.
- Create a database context.
- And seed with data for testing with and without scenarios.
Our code looks like this right now,
public class AppContext: DbContext {
public AppContext(DbContextOptions < AppContext > options): base(options) {}
public class Test {
public int Id {
get;
set;
}
public EnumsHandler.Colors SelectedColor {
get;
set;
}
}
public DbSet < Test > Tests {
get;
set;
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity < Test > ().HasData(new Test {
Id = 1, SelectedColor = EnumsHandler.Colors.BLUE
});
modelBuilder.Entity < Test > ().HasData(new Test {
Id = 2, SelectedColor = EnumsHandler.Colors.GREEN
});
modelBuilder.Entity < Test > ().HasData(new Test {
Id = 3, SelectedColor = EnumsHandler.Colors.RED
});
modelBuilder.Entity < Test > ().HasData(new Test {
Id = 4, SelectedColor = EnumsHandler.Colors.BLUE | EnumsHandler.Colors.GREEN
});
modelBuilder.Entity < Test > ().HasData(new Test {
Id = 5, SelectedColor = EnumsHandler.Colors.GREEN | EnumsHandler.Colors.RED
});
modelBuilder.Entity < Test > ().HasData(new Test {
Id = 6, SelectedColor = EnumsHandler.Colors.BLUE | EnumsHandler.Colors.GREEN | EnumsHandler.Colors.RED
});
}
}
This is how it is stored in our DB.
Now, we will add the converter in the OnModelCreating Method inside our DbContext implementation i.e. AppContext. Below is the code.
var colorConverter = new ValueConverter<EnumsHandler.Colors, string>(
v => v.ToString(),
v => (EnumsHandler.Colors)Enum.Parse(typeof(EnumsHandler.Colors), v));
modelBuilder.Entity<Test>()
.Property(c => c.SelectedColor)
.HasConversion(colorConverter);
Now, our output looks like below.
That’s it. Thanks for reading till the end. Let us summarize what has been covered.
Summary
- We took an overview of what enums are.
- How to extend the enums.
- Validating enums in Web API.
- Creating Nullable enums.
- Saving and Converting enums to and from in Database using Entity Framework Core.
Thanks for reading. Hope you found this useful.