← Back
Milan Jovanovic June 26, 2026 2m

Union types are FINALLY coming to C#

Read full transcript 3 segments
  1. C# is finally getting union types and C# is finally getting union types and this fixes something that has annoyed us this fixes something that has annoyed us this fixes something that has annoyed us for like 20 years. Let me show you with for like 20 years. Let me show you with for like 20 years. Let me show you with an example. Up until now, we didn't have an example. Up until now, we didn't have an example. Up until now, we didn't have a good way of expressing that a method a good way of expressing that a method a good way of expressing that a method could return more than one thing. If we could return more than one thing. If we could return more than one thing. If we look at this get user or throw method, look at this get user or throw method, look at this get user or throw method, it can return a user in the happy path it can return a user in the happy path it can return a user in the happy path or throw an exception in the failure or throw an exception in the failure or throw an exception in the failure path. Now, this isn't transparent to the path. Now, this isn't transparent to the path. Now, this isn't transparent to the caller. They don't know that this throws caller. They don't know that this throws caller. They don't know that this throws an exception until they actually run an exception until they actually run an exception until they actually run into an exception and we used to go into an exception and we used to go into an exception and we used to go around this with things like tuples, around this with things like tuples, around this with things like tuples, implementing the result pattern, or implementing the result pattern, or implementing the result pattern, or maybe using the one-off library. maybe using the one-off library. maybe using the one-off library. However, this all changes with .NET 11 However, this all changes with .NET 11 However, this all changes with .NET 11 and the introduction of union types. A and the introduction of union types. A and the introduction of union types. A union type lets us express a type that union type lets us express a type that union type lets us express a type that consists of a closed set of types and to consists of a closed set of types and to consists of a closed set of types and to give you an example of that, you say give you an example of that, you say give you an example of that, you say public union, this is the syntax, and public union, this is the syntax, and public union, this is the syntax, and we're going to create a user result. The we're going to create a user result. The we're going to create a user result. The syntax is similar to using a primary syntax is similar to using a primary syntax is similar to using a primary constructor, except here you just define constructor, except here you just define constructor, except here you just define the types that are part of the union.

  2. the types that are part of the union. the types that are part of the union. And now that we have our union type, And now that we have our union type, And now that we have our union type, let's see how this improves our code. We let's see how this improves our code. We let's see how this improves our code. We can rewrite our original get user or can rewrite our original get user or can rewrite our original get user or throw method to the more expressive throw method to the more expressive throw method to the more expressive version returning a user result, so we version returning a user result, so we version returning a user result, so we can return union types from methods and can return union types from methods and can return union types from methods and this can either be a user instance on this can either be a user instance on this can either be a user instance on the happy path or a not found instance the happy path or a not found instance the happy path or a not found instance in the failure path. And to consume a in the failure path. And to consume a in the failure path. And to consume a union type, you use a switch expression. union type, you use a switch expression. union type, you use a switch expression. So, switch over the union instance and So, switch over the union instance and So, switch over the union instance and you consume the individual types. So, you consume the individual types. So, you consume the individual types. So, you define what happens if the instance you define what happens if the instance you define what happens if the instance is a user or what happens if the user is is a user or what happens if the user is is a user or what happens if the user is not found. The great thing is that this not found. The great thing is that this not found. The great thing is that this is exhaustive and if you omit a union is exhaustive and if you omit a union is exhaustive and if you omit a union member, you're going to get a compiler member, you're going to get a compiler member, you're going to get a compiler error. So, let's say I leave out not error. So, let's say I leave out not error. So, let's say I leave out not found on purpose and I try to run our found on purpose and I try to run our found on purpose and I try to run our demo, you'll see that we get a build demo, you'll see that we get a build demo, you'll see that we get a build warning. This is current as of .NET 11 warning. This is current as of .NET 11 warning. This is current as of .NET 11 preview five and we also get a runtime preview five and we also get a runtime preview five and we also get a runtime exception that our switch expression is exception that our switch expression is exception that our switch expression is non-exhaustive, and that we didn't cover non-exhaustive, and that we didn't cover non-exhaustive, and that we didn't cover the not found path. If I return this the not found path. If I return this the not found path. If I return this back in our code, and I rerun the back in our code, and I rerun the back in our code, and I rerun the example, you will see that both the old example, you will see that both the old example, you will see that both the old exception approach and the new union exception approach and the new union exception approach and the new union type approach complete successfully. If type approach complete successfully. If type approach complete successfully. If you want to learn more about working you want to learn more about working you want to learn more about working with union types in C#, I highly with union types in C#, I highly with union types in C#, I highly recommend taking a look at the build recommend taking a look at the build recommend taking a look at the build session from Mads and Dustin that goes session from Mads and Dustin that goes session from Mads and Dustin that goes over this in much more detail. I'm going over this in much more detail. I'm going over this in much more detail. I'm going to leave the link to this in the to leave the link to this in the to leave the link to this in the description of this video as well as the description of this video as well as the description of this video as well as the pinned comment. Now, over to you. Let me pinned comment. Now, over to you. Let me pinned comment. Now, over to you. Let me know in the comments what you think know in the comments what you think know in the comments what you think about the upcoming union types that we

  3. about the upcoming union types that we about the upcoming union types that we are getting with the next version of C#.

Summary

C# is introducing union types to address the long-standing issue of clearly representing methods that can return multiple distinct outcomes, moving beyond workarounds like tuples or the result pattern. This new feature, demonstrated through a "get user or throw" example which now explicitly returns a `UserResult` type, provides compile-time safety by ensuring all possible union members are handled, leading to more robust and transparent code. The practical takeaway is that union types offer an expressive and safe way to model varied return values, improving developer clarity and reducing runtime errors.

View original episode ↗