Dunet 1.4.1-preview2
See the version list below for details.
dotnet add package Dunet --version 1.4.1-preview2
NuGet\Install-Package Dunet -Version 1.4.1-preview2
<PackageReference Include="Dunet" Version="1.4.1-preview2"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Dunet" Version="1.4.1-preview2" />
<PackageReference Include="Dunet"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Dunet --version 1.4.1-preview2
#r "nuget: Dunet, 1.4.1-preview2"
#:package Dunet@1.4.1-preview2
#addin nuget:?package=Dunet&version=1.4.1-preview2&prerelease
#tool nuget:?package=Dunet&version=1.4.1-preview2&prerelease
Dunet
Dunet is a simple source generator for discriminated unions in C#.
Install
- NuGet:
dotnet add package dunet
Usage
// 1. Import the namespace.
using Dunet;
// 2. Add the `Union` attribute to a partial record.
[Union]
partial record Shape
{
// 3. Define the union members as inner partial records.
partial record Circle(double Radius);
partial record Rectangle(double Length, double Width);
partial record Triangle(double Base, double Height);
}
// 4. Use the union members.
var shape = new Shape.Rectangle(3, 4);
var area = shape.Match(
circle => 3.14 * circle.Radius * circle.Radius,
rectangle => rectangle.Length * rectangle.Width,
triangle => triangle.Base * triangle.Height / 2
);
Console.WriteLine(area); // "12"
Generics Support
Use generics for more advanced union types. For example, an option monad:
// 1. Import the namespace.
using Dunet;
// Optional: use aliasing for more terse code.
using static Option<int>;
// 2. Add the `Union` attribute to a partial record.
// 3. Add one or more type arguments to the union record.
[Union]
partial record Option<T>
{
partial record Some(T Value);
partial record None();
}
// 4. Use the union members.
Option<int> ParseInt(string? value) =>
int.TryParse(value, out var number)
? new Some(number)
: new None();
string GetOutput(Option<int> number) =>
number.Match(
some => some.Value.ToString(),
none => "Invalid input!"
);
var input = Console.ReadLine(); // User inputs "not a number".
var result = ParseInt(input);
var output = GetOutput(result);
Console.WriteLine(output); // "Invalid input!"
input = Console.ReadLine(); // User inputs "12345".
result = ParseInt(input);
output = GetOutput(result);
Console.WriteLine(output); // "12345".
Implicit Conversion Support
Given a union type where all members contain only a single parameter and all parameters are a different type, Dunet will generate implicit conversions between their values and the union type.
For example, consider a Result union type that represents success
as a double and failure as an Exception:
// 1. Import the namespace.
using Dunet;
// 2. Define a union type with single unique member values:
[Union]
partial record Result
{
partial record Success(double Value);
partial record Failure(Exception Error);
}
// 3. Return union member values directly.
Result Divide(double numerator, double denominator)
{
if (denominator is 0d)
{
// No need for `new Result.Failure(new InvalidOperationException("..."));`
return new InvalidOperationException("Cannot divide by zero!");
}
// No need for `new Result.Success(...);`
return numerator / denominator;
}
var result = Divide(42, 0);
var output = result.Match(
success => success.Value.ToString(),
failure => failure.Error.Message
);
Console.WriteLine(output); // "Cannot divide by zero!"
Async Match Support
Dunet generates a MatchAsync() extension method for all Task<T> and ValueTask<T> where T is a union type. For example:
// Choice.cs
using Dunet;
namespace Core;
// 1. Define a union type within a namespace.
[Union]
partial record Choice
{
partial record Yes;
partial record No(string Reason);
}
// Program.cs
using Core;
using static Core.Choice;
// 2. Define async methods like you would for any other type.
static async Task<Choice> AskAsync()
{
// Simulating network call.
await Task.Delay(1000);
// 3. Return unions from async methods like any other type.
return new No("because I don't wanna!");
}
// 4. Asynchronously match any union `Task` or `ValueTask`.
var response = await AskAsync().MatchAsync(yes => "Yes!!!", no => $"No, {no.Reason}");
Console.WriteLine(response); // Prints "No, because I don't wanna!" after 1 second.
Note:
MatchAsync()can only be generated for namespaced unions.
Nested Union Support
To declare a union nested within a class or record, the class or record must be partial. For example:
// This type declaration must be partial.
public partial class Parent1
{
// So must this one.
public partial class Parent2
{
// Unions must always be partial.
[Union]
public partial record Nested
{
public partial record Member1;
public partial record Member2;
}
}
}
// Access union members like any other nested type.
var member1 = new Parent1.Parent2.Nested.Member1();
Samples
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 4.3.1)
NuGet packages (10)
Showing the top 5 NuGet packages that depend on Dunet:
| Package | Downloads |
|---|---|
|
ZeroC.Slice
Slice for C#. |
|
|
InsurScan.Models
API contracts for InsurScan platform. Contains request/response models for building custom clients or integrating with the InsurScan API. |
|
|
Xenial.Identity.Client
Package Description |
|
|
TeaPie
The core of TeaPie.Tool in form of library. |
|
|
Morphir
Morphir executable package for AOT and single-file deployments |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 1.16.2 | 675 | 4/25/2026 | |
| 1.16.1 | 22,834 | 2/16/2026 | |
| 1.16.0 | 241 | 2/14/2026 | |
| 1.15.0 | 5,967 | 1/29/2026 | |
| 1.14.0 | 23,426 | 1/27/2026 | |
| 1.13.1 | 1,091 | 1/25/2026 | |
| 1.13.0 | 293 | 1/25/2026 | |
| 1.13.0-preview2 | 103 | 1/25/2026 | |
| 1.13.0-preview1 | 104 | 1/25/2026 | |
| 1.12.0 | 2,112 | 1/19/2026 | |
| 1.12.0-preview1 | 109 | 1/19/2026 | |
| 1.11.4 | 1,484 | 1/17/2026 | |
| 1.11.4-preview3 | 108 | 1/17/2026 | |
| 1.11.4-preview2 | 119 | 1/17/2026 | |
| 1.11.4-preview1 | 117 | 1/17/2026 | |
| 1.11.3 | 94,126 | 6/13/2025 | |
| 1.11.2 | 230,071 | 1/29/2024 | |
| 1.11.1 | 563 | 1/27/2024 | |
| 1.11.0 | 9,015 | 1/4/2024 | |
| 1.4.1-preview2 | 1,611 | 11/5/2022 |
1.4.1-preview2 - Disable CS1591 in generated extensions.
1.4.1-preview1 - Disable CS1591 in generated code.
1.4.0 - Support Action match functions.
1.3.0 - Async match methods.
1.2.0 - Support nested union declarations.
1.1.0 - Add implicit conversions for union members.
1.0.2 - Support multiple unions with the same name.
1.0.1 - Configure Dunet as development dependency.
1.0.0 - Production release.
0.5.0 - Generate dedicated match method on union records.
0.4.0 - Add support for declaring a union with records.
0.3.0 - Support complex types in union members.
0.2.2 - Add source generator DLL to package.
0.2.1 - Update readme.
0.2.0 - Generate dedicated match method.
0.1.3 - Add support for declaring unions inside top level programs.
0.1.2 - Simplify generated source.
0.1.1 - Support any number of interfaces.
0.1.0 - Initial release.