Unions are one of those features that have been requested for years, and in .NET 11 (or rather, C# 15) they're finally here. In this post I describe what that support looks like, how you can use them, how they're implemented, and how you can implement your own custom types.
This post was written using the features available in .NET 11 preview 4. Many things may change between now and the final release of .NET 11.
Unions are one of those basic data structures which are used all the time in the functional programming world; they're available in F#, TypeScript, Rust…pretty much any functional-first language. There are many different types of union, but at their core they allow having a type that can represent two different things.
Some of the simplest union types are the Option<T> and Result<TSuccess, TError> types. There's no "standard" version of these, but it's super common to see custom implementations. Result<> is one of the easiest to explain as it can be in one of two states:
Success—in this case the Result<> object contains a TSuccess value representing the "success" result for an operation that succeeded.
object contains a value representing the "success" result for an operation that succeeded. Error—in this case the Result<> object contains a TError value representing the "error" for an operation that failed.
You return a Result<> object from your method, and then the caller has to explicitly handle both cases instead of assuming success.
This pattern is often called the result pattern and it has both pros and cons in C#. I wrote a series about using this pattern, as well as considering whether it's worth it here.
Union types don't have to be the super generic form like this though. They can be used to represent any arbitrary combined set of types.
In the previous section I used the classic Result<> type as an example of a union, but unions are far more versatile than that. They're ideal whenever you want to deal with data that could be one of several potentially unrelated types.
... continue reading