OneOf for C# (.NET): Complete Guide with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

OneOf for C# (.NET): Complete Guide with Examples

The OneOf library brings discriminated unions to C#. It solves a fundamental problem: how to elegantly represent a value that can be one of several known types in a statically-typed language. Instead of using object with type casting, Nullable, or building class hierarchies, OneOf provides a type-safe and expressive way to work with such values.

Why use it? First, it boosts code readability: a method returning OneOf<Success, Error> immediately signals the operation can succeed or fail. Second, it eliminates a whole class of bugs caused by incorrect type casting. Third, OneOf forces you to handle all possible cases, making your code more robust and predictable. This is especially useful in scenarios where exceptions (for control flow) or returning null are traditionally used.

OneOf fits perfectly into functional programming styles in C#. It lets you model your domain more precisely: instead of a Result class with flags and nested objects, you can use OneOf<T0, T1, T2> where each type represents one possible state. This makes your code more declarative and reduces the number of if-else constructs.

Installation

Install the library via NuGet Package Manager. Run one of the following commands depending on your tool:

# Package Manager Console
Install-Package OneOf

# .NET CLI
dotnet add package OneOf

# PackageReference (manually in .csproj)
<PackageReference Include="OneOf" Version="3.0.271" />

After installation, add using OneOf; at the top of your file.

Quick Start

Let's look at a simple example: a function that divides one number by another. Instead of throwing an exception on division by zero, we return OneOf<double, string> — either the result or an error message.

using OneOf;

public OneOf<double, string> SafeDivide(double a, double b)
{
    if (b == 0)
        return "Error: division by zero";
    return a / b;
}

// Usage
var result = SafeDivide(10, 2);

result.Switch(
    value => Console.WriteLine($"Result: {value}"),
    error => Console.WriteLine($"Error: {error}")
);

// Output: Result: 5

Notice: no out parameters, no null checks, no exception handling. All you need is to call Switch or Match and provide handlers for each possible case.

Key Methods and Classes

The library provides several core mechanisms for working with discriminated unions. Let's dive into each one.

1. OneOf<T0, T1, ...>

Signature: public class OneOf<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : IOneOf

What it does: The base class representing a value that can be one of the specified types. Supports up to 9 types. Implicit conversion from any of the specified types to OneOf.

OneOf<int, string, bool> value = 42; // implicit conversion
value = "hello";
value = true;

// Explicit creation
var explicitValue = new OneOf<int, string>(100);

2. Switch

Signature: public void Switch(Action<T0> f0, Action<T1> f1, ...)

What it does: Executes one of the provided actions depending on which value the OneOf holds. Returns nothing.

Recommendations