Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Derek Comartin
11m 03s
In C#, conditional statements like the if statement, if else statement, and switch statement are essential tools. But what happens when these constructs are used excessively - especially tied to enums? Derek Comartin, in his video "Enums Aren't Evil. Conditionals Everywhere Are", takes us through a detailed refactor that replaces widespread conditional logic with cleaner, more maintainable patterns.
In this article, we'll walk through Derek's reasoning step by step, using his timestamps as anchors. We'll also explore how his ideas apply to common conditional patterns in C# like the ternary operator, else statement, and switch-case structures - highlighting where these can cause problems in large codebases and how you can refactor toward better design.
Derek starts by showcasing an if statement that checks the product type:
if (productType == ProductType.Template || productType == ProductType.Ebook)If productType = ProductType.Template OrElse productType = ProductType.Ebook ThenAt first glance, the conditional if above looks straightforward. But Derek warns that this kind of statement evaluates a given condition and then executes a block of code only if the condition is true - which becomes problematic when this logic is repeated everywhere.
You might have this block again in another method or class:
if (offeringType == ProductType.Template || offeringType == ProductType.Ebook)If offeringType = ProductType.Template OrElse offeringType = ProductType.Ebook ThenDerek explains that this pattern quickly spreads across a large system. The same if else logic appears in multiple services, causing inconsistencies and bugs when adding a new enum value. For example, what happens when you introduce a new product type like Video? You'll have to remember to update every single block where this conditional expression exists.
In the following example, Derek drills into nested conditionals. Inside one method, an if else statement checks the same enum, and that result is passed to yet another method, which also contains a similar check.
The statement checks for Template or Ebook, and returns something - otherwise, it returns null. Derek notes that this redundancy doesn't just make the code longer, it introduces maintenance hazards. The same logic is copied across multiple files, leading to control flow chaos.
If your system requires you to add a default case every time you touch an enum, you know something's off.
Instead of constantly checking types with if else, Derek proposes asking a better question:
Does the product have downloadable characteristics?
This is a better expression of intent. It makes your code more readable and reduces reliance on the enum entirely. Rather than writing an if statement with two conditions like:
if (product.Type == ProductType.Template || product.Type == ProductType.Ebook)If product.Type = ProductType.Template OrElse product.Type = ProductType.Ebook ThenYou can simply encapsulate that logic in a model and write:
if (product.HasDownloadableResource())If product.HasDownloadableResource() ThenThis returns true only when a downloadable resource is present - reducing the need for complex conditional expressions.
To solve the core issue, Derek introduces a DownloadableResource type. This type includes a download URL and a default filename. It becomes a first-class part of your domain, rather than relying on if statements to derive it.
Now, instead of repeating this:
if (product.Type == ProductType.Template)
{
// Generate file name
}
else if (product.Type == ProductType.Ebook)
{
// Generate file name
}If product.Type = ProductType.Template Then
' Generate file name
ElseIf product.Type = ProductType.Ebook Then
' Generate file name
End IfYou write this:
var downloadable = product.GetDownloadableResource();
if (downloadable != null)
{
Console.WriteLine(downloadable.FileName);
}Dim downloadable = product.GetDownloadableResource()
If downloadable IsNot Nothing Then
Console.WriteLine(downloadable.FileName)
End IfThis simplifies logic dramatically and eliminates the need for else statement branches or even a switch statement.
Derek takes it further by explaining a significant design choice: shifting logic from compile-time to runtime. This means querying the system at runtime to see if a DownloadableResource exists for a product. If it does, act on it. If not, skip it.
He notes that this move turns static if else logic into runtime queries. It might add a database call, but it reduces nested if else logic and centralizes behavior. This improves maintainability at scale.
Another route Derek explores is inheritance. You can create an abstract base class Product and then define derived types like Ebook, Template, or OfflineCourse.
Each one overrides methods like:
public virtual string GetDownloadUrl() { ... }Public Overridable Function GetDownloadUrl() As String
' ...
End FunctionThis approach allows each product to handle its own logic. While this avoids a switch statement or multiple conditional statements, Derek points out that you can still end up writing conditional expressions internally if you're not careful.
If inheritance feels heavy-handed, Derek suggests using explicit types like DownloadableProduct, which contains its own properties and methods - without being tied to a hierarchy.
In your program, this could look like:
var downloader = new DownloadableProduct(product);
Console.WriteLine(downloader.GetDefaultFileName());Dim downloader = New DownloadableProduct(product)
Console.WriteLine(downloader.GetDefaultFileName())There's no need for an if else or switch statement to determine the behavior - each object knows what to do.
If you're not ready to abandon enums, Derek proposes a lightweight solution - create an extension method:
public static bool IsDownloadable(this ProductType type)
{
return type == ProductType.Template || type == ProductType.Ebook;
}Public Shared Function IsDownloadable(type As ProductType) As Boolean
Return type = ProductType.Template OrElse type = ProductType.Ebook
End FunctionNow instead of writing:
if (product.Type == ProductType.Template || product.Type == ProductType.Ebook)If product.Type = ProductType.Template OrElse product.Type = ProductType.Ebook ThenYou can simplify it to:
if (product.Type.IsDownloadable())If product.Type.IsDownloadable() ThenThis centralizes your logic and avoids repeating the curly brackets and block of code again and again.
Derek also cautions against overusing shorthand like the ternary operator:
string filename = product.Type == ProductType.Template ? "template.pdf" : "default.pdf";Dim filename As String = If(product.Type = ProductType.Template, "template.pdf", "default.pdf")While it's valid syntax, it can be error-prone and hard to read when logic gets complex. Especially if your condition evaluates to false, the wrong value might be assigned in subtle ways.
Similarly, switch with a break statement and default case also falls into this trap. It's better to ask objects for behavior than use switch-case logic.
In conclusion, Derek's video is not an attack on enums - but a critique of how we use conditional if structures around them. By spreading if else and switch statements across your codebase, you make the system harder to test, maintain, and evolve.
Whether you opt for encapsulation, runtime lookup, inheritance, or simple extension methods, the goal remains the same: reduce conditionals, and move logic to where it belongs.
Remember:
As Derek says, "It depends on your context." But one thing is certain: a product isn't always just a product - sometimes, it's a signal to rethink your design.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy