Dusharp 0.5.2
See the version list below for details.
dotnet add package Dusharp --version 0.5.2
NuGet\Install-Package Dusharp -Version 0.5.2
<PackageReference Include="Dusharp" Version="0.5.2"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Dusharp" Version="0.5.2" />
<PackageReference Include="Dusharp"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Dusharp --version 0.5.2
#r "nuget: Dusharp, 0.5.2"
#:package Dusharp@0.5.2
#addin nuget:?package=Dusharp&version=0.5.2
#tool nuget:?package=Dusharp&version=0.5.2
Dusharp
Dusharp is a C# source generator library for creating discriminated unions. This library allows you to define union types with ease, using attributes and partial methods. It is inspired by functional languages but built for C# developers.
Features
- ✅ Create unions: Define discriminated unions using attributes.
- ✅ Match method: Pattern match on union cases in a type-safe way.
- ✅ Equality: Automatic equality comparison for unions.
- ✅ Generics: Generics support for union types.
- ✅ Pretty print: Using overloaded
ToString(). - ✅ Struct unions: With efficient memory layout for unions as structs.
- ❌ JSON serialization/deserialization: Support for unions with
System.Text.Json(coming soon).
Installation
Dusharp is available as a NuGet package. You can install it using the NuGet package manager:
dotnet add package Dusharp
Usage
Dusharp uses attributes to generate discriminated unions and case methods. Here's how to get started:
1. Define a Union
To define a union, annotate a class with the [Dusharp.UnionAttribute] attribute.
using Dusharp;
[Union]
public partial class Shape<T>
where T : struct, INumber<T>
{
}
2. Define Union Cases
Define union cases by creating public static partial methods and marking them with the [Dusharp.UnionCaseAttribute] attribute. The method body will be automatically generated.
using Dusharp;
[Union]
public partial class Shape<T>
where T : struct, INumber<T>
{
[UnionCase]
public static partial Shape<T> Circle(T radius);
[UnionCase]
public static partial Shape<T> Rectangle(T width, T height);
}
3. Match on Union
You can easily perform pattern matching on a union using the Match method. The source generator will create the Match method based on the defined union cases.
Shape<double> shape = Shape<double>.Circle(5.0);
string result = shape.Match(
radius => $"Circle with radius {radius}",
(width, height) => $"Rectangle with width {width} and height {height}");
Console.WriteLine(result); // Output: Circle with radius 5.0
4. Compare Unions
Union cases can be compared for equality using the auto-generated equality methods. This allows for checking if two unions are the same.
Shape<double> shape1 = Shape<double>.Circle(5.0);
Shape<double> shape2 = Shape<double>.Circle(5.0);
Console.WriteLine(shape1.Equals(shape2)); // True
Console.WriteLine(shape1 == shape2); // True
Struct unions
Dusharp supports struct unions, allowing you to reduce allocations. You can define struct union the same way as for class union using the [Dusharp.UnionAttribute] attribute. This feature generates memory efficient unions.
Blittable Types
Blittable types (e.g., int, double, etc., and structs contain only blittable types) from different cases will share the same memory space using the [StructLayout(LayoutKind.Explicit)] attribute. This enables efficient memory usage by overlapping the fields in the union.
Reference Types
For reference type parameters, Dusharp uses a shared object fields to store reference type parameters from different cases. The object fields will be cast to their target types using the no-op Unsafe.As method, providing an efficient way to handle reference types in struct unions.
Example
For instance, consider a union that contains both blittable and reference type parameters:
[Union]
public partial struct TestUnion
{
[UnionCase]
public static partial TestUnion Case1(long value1, long value2);
[UnionCase]
public static partial TestUnion Case2(Guid value1, Guid value2);
[UnionCase]
public static partial TestUnion Case3(string value, Exception value2);
[UnionCase]
public static partial TestUnion Case4(Action value);
}
Generated Code Explanation
The source generator produces efficient code for this union by optimizing how blittable and reference types are stored and managed in memory. Here's the structure of the generated code:
partial struct TestUnion : System.IEquatable<TestUnion>
{
private object Field0;
private object Field1;
private TestUnionBlittableData UnionBlittableDataField;
private byte Index;
}
Field0andField1are used to store reference type parameters (e.g.,string,Exception,Action). Reference types share the same object references in memory.UnionBlittableDataFieldis an instance ofTestUnionBlittableData, where the blittable data (e.g.,long,Guid) is stored.Indextracks the active case, allowing theMatchand equality methods to know which union case is currently stored.
Memory Layout Optimization for Blittable Types
For blittable types, the generator uses a memory-efficient layout where the fields of different union cases are overlapped in memory using the [StructLayout(LayoutKind.Explicit)] attribute. This reduces memory usage by sharing memory space for compatible types.
[StructLayout(LayoutKind.Explicit)]
internal struct TestUnionBlittableData
{
[FieldOffset(0)]
public Case1BlittableData Case1Data;
[FieldOffset(0)]
public Case2BlittableData Case2Data;
[StructLayout(LayoutKind.Auto)]
public struct Case1BlittableData
{
public long value1;
public long value2;
}
[StructLayout(LayoutKind.Auto)]
public struct Case2BlittableData
{
public System.Guid value1;
public System.Guid value2;
}
}
TestUnionBlittableDatacontains the blittable data for the union cases that involvelongandGuidtypes.FieldOffset(0)ensures that the memory space forCase1DataandCase2Datais shared, meaning both cases will occupy the same memory region. This is a key feature that allows for efficient memory usage when dealing with blittable types.
Size of a union
In this example, the size of the TestUnion union is 56 bytes:
- 2
objectfields: 16 bytes (each object reference is 8 bytes on a 64-bit system) TestUnionBlittableData: 32 bytes (the size of the largest blittable case, which contains 2Guidparameters, each being 16 bytes)Indexfield: 1 byte + padding for alignment, which totals 8 bytes
Thus, the total size is 16 + 32 + 8 = 56 bytes.
Important Note
All of these details about memory layout and struct size are implementation-specific and subject to change. Users should not rely on these internal details or use them directly in their code. The behavior and memory management may evolve in future versions to improve performance or efficiency.
Upcoming Features
- JSON serialization/deserialization: Support for JSON (de)serialization via System.Text.Json.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Dusharp:
| Package | Downloads |
|---|---|
|
Dusharp.Json
System.Text.Json support for Dusharp. |
|
|
Dusharp.Newtonsoft
Newtonsoft.Json support for Dusharp. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.2 | 1,053 | 11/2/2025 |
| 0.7.1 | 313 | 10/29/2025 |
| 0.7.0 | 416 | 4/25/2025 |
| 0.6.2 | 240 | 1/10/2025 |
| 0.6.1 | 189 | 1/9/2025 |
| 0.6.0 | 219 | 1/7/2025 |
| 0.6.0-rc.1 | 139 | 1/7/2025 |
| 0.5.3 | 264 | 10/12/2024 |
| 0.5.2 | 217 | 10/1/2024 |
| 0.5.1 | 190 | 9/30/2024 |
| 0.5.0 | 230 | 9/29/2024 |
| 0.4.0 | 284 | 9/14/2024 |
| 0.3.0 | 213 | 9/13/2024 |
| 0.2.0 | 246 | 9/12/2024 |