C# - Enums and Bug Resilience
Aviad Pineles
Posted on September 27, 2021
Our domain is made of sets. Some sets are trivial such as all integers (int
) or all booleans (bool
) but often we are dealing with sets that are more narrow, for example the possible states of an order (Incomplete
, Unpaid
, Paid
, Shipped
, etc.).
In our database we assign a number or a string that represents each possible value, and in our code we use an Enum
for that. This is good, but if we are not careful, then at some point in the future, when we change the composition of the set (for example by adding another state Received
), we might create hard to debug errors in our program.
We want to always use switch
when dealing with these sets, so that when the set changes, the compiler automatically warns us about all the places where code might need to be changed.
However there's one case where this is tricky: when dealing with the database. For example, we have a query in our code that fetches all orders that are paid, so our LINQ condition could be something like this:
where order.status == OrderStatus.Paid ||
order.status == OrderStatus.Shipped
But what happens when we now add the new Received
state? This query is now broken because received orders are also paid, but the compiler doesn't have any way of knowing that!
We need to somehow add a switch
to this operation to make it safe. What we must do is filter all the elements of the enum by our condition:
IEnumerable<OrderStatus> GetOrderStatusValuesWhichArePaid() {
static bool IsPaid(OrderStatus orderStatus) => orderStatus switch {
OrderkStatus.Incomplete => false,
OrderkStatus.Unpaid => false,
OrderkStatus.Paid => true,
OrderkStatus.Shipped => true,
_ => throw new ArgumentOutOfRangeException(nameof(orderStatus))
};
return Enum.GetValues<OrderStatus>().Where(IsPaid);
}
And we can use it in our LINQ query:
var paidStatusValues = GetOrderStatusValuesWhichArePaid();
var query = from order in Orders
where paidStatusValues.Contains(order.status)
select order;
Now when we add the new Received
state, the compiler can warn us that the switch statement in the function IsPaid
is not covering all cases properly.
Posted on September 27, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.