Introduction

Handling multiple possible outcomes is a common requirement in modern applications. For example, an API might return a successful result, a validation error, or a "not found" response. Traditionally, C# developers have handled these scenarios using inheritance, exceptions, tuples, or custom result classes.

With the introduction of Union Types in .NET 11, C# provides a cleaner and more expressive way to represent values that can be one of several different types. This feature helps developers write more readable, maintainable, and type-safe code.

In this article, we'll explore what Union Types are, why they are useful, and when you should consider using them in your applications.

What Are Union Types?

A Union Type allows a variable or return value to represent one of multiple predefined types.

Instead of creating several wrapper classes or relying on exceptions for normal application flow, a Union Type clearly defines all possible outcomes.

Think of it as saying:

"This method can return either a successful result or an error."

This makes your code easier to understand because every possible outcome is explicitly defined.

Why Are Union Types Useful?

Before Union Types, developers often used approaches like:

While these methods work, they can make the code harder to maintain and understand.

Union Types improve this by:

A Simple Example

Imagine you're searching for a user in a database.

Without Union Types, you might write:

public User? GetUser(int id)
{
    // Fetch user
}

The caller now has to determine whether a null value means the user doesn't exist or something else went wrong.

With Union Types, the method can explicitly describe every possible result.

For example:

public UserResult GetUser(int id)
{
    // Returns either:
    // - User
    // - NotFound
}

Now the intent is much clearer.

Practical API Scenario

Suppose you're building an ASP.NET Core API.

When a client requests an order, there are several possible outcomes:

Instead of relying on exceptions or multiple if statements, a Union Type can represent these outcomes in a single, well-defined return type.

This makes both the API implementation and the client code easier to follow.

Benefits of Union Types

Better Readability

Developers can quickly understand what a method returns without reading its implementation.

Instead of guessing whether null or an exception indicates failure, the return type clearly communicates every possible outcome.

Improved Type Safety

Because the compiler knows every supported type, it can help detect mistakes before your application runs.

This reduces runtime errors and improves code quality.

Cleaner Error Handling

Exceptions should generally represent unexpected situations.

Validation failures or missing records are often expected outcomes and can be represented more naturally using Union Types.

Easier Maintenance

As applications grow, methods often gain additional return scenarios.

Union Types make it easier to extend functionality without introducing complicated inheritance hierarchies or multiple wrapper classes.

Comparing Traditional Approaches

Traditional ApproachLimitationUnion Types Advantage
Returning nullEasy to forget null checksExplicit result types
ExceptionsCan affect performance for expected outcomesClear success and failure paths
object return typeNo compile-time safetyStrongly typed results
Custom wrapper classesMore boilerplate codeSimpler and easier to understand

Real-World Use Cases

Union Types work especially well in situations like:

For example, a payment process might return:

Representing these outcomes with a Union Type makes the code much more expressive than relying on exceptions or status codes alone.

Best Practices

When using Union Types, keep these recommendations in mind:

Following these practices helps keep your code clean and easy to maintain.

When Should You Use Union Types?

Union Types are a good choice when:

They may not be necessary for very simple methods that always return a single value.

Conclusion

Union Types are a valuable addition to the C# language and the .NET ecosystem. They provide a more expressive way to represent multiple valid outcomes while improving readability, maintainability, and type safety.

Instead of relying on null values, exceptions, or complex inheritance structures, developers can clearly define every possible result a method can return. This leads to cleaner APIs, simpler business logic, and code that is easier for teams to understand and maintain.

As .NET continues to evolve, features like Union Types help developers write more robust and modern applications with less boilerplate and clearer intent.