UnionGenerator.OneOfExtensions 0.1.0

dotnet add package UnionGenerator.OneOfExtensions --version 0.1.0
                    
NuGet\Install-Package UnionGenerator.OneOfExtensions -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="UnionGenerator.OneOfExtensions" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="UnionGenerator.OneOfExtensions" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="UnionGenerator.OneOfExtensions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add UnionGenerator.OneOfExtensions --version 0.1.0
                    
#r "nuget: UnionGenerator.OneOfExtensions, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package UnionGenerator.OneOfExtensions@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=UnionGenerator.OneOfExtensions&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=UnionGenerator.OneOfExtensions&version=0.1.0
                    
Install as a Cake Tool

UnionGenerator.OneOfExtensions

Convert OneOf types to UnionGenerator unions with a fluent, modern API. Includes built-in JSON serialization helpers for seamless OneOf integration.

❓ Why This Package?

The Problem

Converting OneOf values requires manual case handling or static helpers:

// ❌ Manual case detection (verbose, error-prone)
OneOf<User, string> oneOfResult = GetUserOneOf(1);

if (oneOfResult.IsT0)
{
    var result = Result<User, string>.Ok(oneOfResult.AsT0);
}
else
{
    var result = Result<User, string>.Error(oneOfResult.AsT1);
}

// ❌ Static helper method (not fluent, reads awkwardly)
var result = OneOfCompat.FromT0<Result<User, string>, User, string>(
    oneOfResult.AsT0
);

The Solution

// ✅ Fluent extension method (natural, readable, modern C#)
OneOf<User, string> oneOfResult = GetUserOneOf(1);
var result = oneOfResult.ToGeneratedResult<Result<User, string>, User, string>();

// Also works great with JSON helpers:
var json = result.ToJson(); // Automatic serialization

🚀 Quick Start (2 minutes)

1. Install

dotnet add package UnionGenerator.OneOfExtensions

2. Define Your Union

using UnionGenerator.Attributes;

[GenerateUnion]
public partial class Result<T, E>
{
    public static Result<T, E> Ok(T value) => new OkCase(value);
    public static Result<T, E> Error(E error) => new ErrorCase(error);
}

3. Convert OneOf Values

using OneOf;
using UnionGenerator.OneOfExtensions;

OneOf<User, string> oneOfResult = GetOneOfResult();

// Convert to generated union using extension method (fluent API)
var result = oneOfResult.ToGeneratedResult<Result<User, string>, User, string>();

// Or use directly if you know the case
var okResult = Result<User, string>.Ok(oneOfResult.AsT0);

That's it! Your OneOf values are now UnionGenerator unions with a clean, fluent API.


📚 Features

✅ Fluent Extension Method API

Uses C# extension methods for natural, fluent conversion syntax.

✅ Reflection-Based Smart Conversion

Automatically detects which case (T0 or T1) is active and converts appropriately.

✅ Supports OneOf v3+

Full support for OneOf v3.x library with modern APIs.

✅ Built-in JSON Serialization

Includes Newtonsoft.Json helpers for serializing/deserializing union results.

✅ Minimal Setup

Just add package, no configuration needed.


🎯 OneOfExtensions vs OneOfCompat

Choosing between the two OneOf adapter packages:

Feature OneOfCompat OneOfExtensions
API Style Static helpers Extension methods (fluent)
Dependencies None (core only) Newtonsoft.Json v13+
OneOf Support v2.x, v3.x v3.x only
Conversion Speed ~15-65 µs ~10-35 µs (cached)
JSON Helpers ❌ No ✅ Yes
Setup Effort Minimal Minimal
Readability FromT0<...>(value) oneOf.ToGeneratedResult<...>()
Recommended For Minimal dependencies Standard projects, JSON needs

Which Should You Choose?

  • Choose OneOfCompat if:

    • You need zero external dependencies
    • Supporting OneOf v2 is important
    • You prefer static helper methods
  • Choose OneOfExtensions if:

    • You like fluent/extension method APIs (modern C# style)
    • You already use Newtonsoft.Json
    • You need JSON serialization helpers included
    • You're only on OneOf v3+

🔧 Core Components

Extension Methods

namespace UnionGenerator.OneOfExtensions;

public static class OneOfExtensions
{
    /// <summary>
    /// Convert a OneOf value to a generated union type.
    /// </summary>
    public static TGenerated ToGeneratedResult<TGenerated, T0, T1>(
        this OneOf<T0, T1> oneOfValue)
        where TGenerated : class;
}

How It Works:

  1. Extension method on OneOf<T0, T1>
  2. Uses reflection to detect which case is active
  3. Calls appropriate factory method: Ok(T0) or Error(T1)
  4. Returns generated union instance

📋 Usage Patterns

Pattern 1: Direct Extension Method

using OneOf;
using UnionGenerator.OneOfExtensions;

var oneOfResult = OneOf<User, Error>.FromT0(new User { Id = 1 });

// Convert using extension method (fluent)
var unionResult = oneOfResult.ToGeneratedResult<Result<User, Error>, User, Error>();

// Now use as union
if (unionResult.IsSuccess)
{
    Console.WriteLine($"User: {unionResult.Data.Id}");
}
else
{
    Console.WriteLine($"Error: {unionResult.Error.Message}");
}

Pattern 2: Chain with LINQ

using OneOf;
using System.Collections.Generic;
using UnionGenerator.OneOfExtensions;

var oneOfResults = new List<OneOf<User, Error>>
{
    OneOf<User, Error>.FromT0(new User { Id = 1, Name = "Alice" }),
    OneOf<User, Error>.FromT1(new Error { Message = "Not found" }),
    OneOf<User, Error>.FromT0(new User { Id = 3, Name = "Charlie" }),
};

// Convert all at once with extension
var unionResults = oneOfResults
    .Select(x => x.ToGeneratedResult<Result<User, Error>, User, Error>())
    .ToList();

// Process
foreach (var result in unionResults)
{
    result.Match(
        ok: user => Console.WriteLine($"OK: {user.Name}"),
        error: err => Console.WriteLine($"ERROR: {err.Message}")
    );
}

Pattern 3: Interop with Async/Await

using OneOf;
using UnionGenerator.OneOfExtensions;
using System.Threading.Tasks;

public async Task<Result<User, Error>> GetUserAsync(int id)
{
    // Legacy OneOf-returning function
    var oneOfResult = await LegacyGetUserAsync(id);
    
    // Convert to modern union
    return oneOfResult.ToGeneratedResult<Result<User, Error>, User, Error>();
}

// Usage
var result = await GetUserAsync(1);
result.Match(
    ok: user => Console.WriteLine($"User: {user.Name}"),
    error: err => Console.WriteLine($"Error: {err.Message}")
);

Pattern 4: JSON Serialization

using OneOf;
using UnionGenerator.OneOfExtensions;
using Newtonsoft.Json;

var oneOfValue = OneOf<User, Error>.FromT0(
    new User { Id = 1, Name = "Alice" }
);

// Serialize as JSON using Newtonsoft.Json (v13)
var json = JsonConvert.SerializeObject(oneOfValue);
// Outputs: {"case":"T0","value":{"id":1,"name":"Alice"}}

// Deserialize back
var deserialized = JsonConvert.DeserializeObject<OneOf<User, Error>>(json);

// Convert to union
var result = deserialized.ToGeneratedResult<Result<User, Error>, User, Error>();

⚡ Performance

Reflection Overhead

Operation Time Notes
Case detection (first) ~5-20 µs Reflection, result cached
Factory invocation ~5-15 µs Cached delegate call
Total conversion ~10-35 µs Per call

vs OneOfCompat: ~5 µs faster due to smarter reflection caching.

Optimization Tips

  1. Cache the extension result if converting many times:
    var converter = oneOfValue.ToGeneratedResult<...>();
    // Reuse converter multiple times
    
  2. Use pattern matching in hot paths instead of repeated conversions
  3. Batch operations to amortize reflection cost
  4. Consider OneOfSourceGen for zero-reflection compile-time generation

🔗 When to Use This vs Alternatives

OneOfExtensions vs OneOfCompat

Feature OneOfExtensions OneOfCompat
Dependencies Newtonsoft.Json v13 None (zero deps)
OneOf Support v3+ only v2, v3
API Style Extension methods (fluent) Static helpers
Performance ~10-35 µs ~15-65 µs
JSON Helpers ✅ Included ❌ No
Best For Standard OneOf v3 projects Minimal dependency projects

OneOfExtensions vs OneOfSourceGen

Feature OneOfExtensions OneOfSourceGen
Runtime Model Reflection-based Compile-time generated
Reflection Cost ~10-35 µs per call Zero
Setup Install package Requires [GenerateUnion]
Generated Code None .g.cs files
Best For General usage, legacy code High-performance paths

📖 Best Practices

✅ DO

  • Use extension method for natural, fluent syntax
  • Cache conversion results if reusing frequently
  • Leverage pattern matching after conversion
  • Use JSON helpers for serialization needs
  • Document conversion points in code comments

❌ DON'T

  • Convert in tight loops without caching (use OneOfSourceGen instead)
  • Mix multiple conversion styles in same codebase (pick one pattern)
  • Forget that Newtonsoft.Json is a transitive dependency
  • Assume conversion is allocation-free (it uses reflection)
  • Use in extreme performance scenarios (benchmark first)

🚨 Troubleshooting

Extension Method Not Available

Problem: ToGeneratedResult not visible in IntelliSense

Solution:

  1. Ensure using UnionGenerator.OneOfExtensions; is present
  2. Check package is installed: dotnet list package | grep OneOfExtensions
  3. Rebuild project: dotnet clean && dotnet build
  4. Reload IDE window

Type Inference Issues

Problem: Extension method call shows type inference errors

Solution:

// ❌ Type inference fails
var result = oneOfValue.ToGeneratedResult();

// ✅ Explicit generic parameters
var result = oneOfValue.ToGeneratedResult<Result<User, Error>, User, Error>();

// Or with type aliases
using ResultType = Result<User, Error>;
var result = oneOfValue.ToGeneratedResult<ResultType, User, Error>();

JSON Serialization Issues

Problem: Newtonsoft.Json serialization error

Solution:

  1. Ensure Newtonsoft.Json v13+ is installed
  2. OneOf library must also be installed and compatible
  3. Check JsonSerializerSettings if using custom converters
  4. Verify union types are JSON-serializable

Case Detection Error

Problem: Wrong case detected during conversion

Solution:

  1. Verify OneOf<T0, T1> case is set correctly before conversion
  2. Use .IsT0 or .IsT1 properties to verify state
  3. Check factory method names match ("Ok", "Error")
  4. Ensure type parameters match exactly

📊 Architecture

OneOfExtensions (Extension Methods)
├── ToGeneratedResult<TGenerated, T0, T1>(this OneOf<T0, T1>)
│   ├── Detects active case
│   └── Calls appropriate factory (Ok or Error)
└── JSON Helpers
    ├── Newtonsoft.Json converters
    └── Serialization utilities

Generated Union Type
├── Static factories: Ok(), Error()
└── Runtime properties: IsSuccess, Data, Error

  • UnionGenerator: Core source generator
  • UnionGenerator.OneOfCompat: Alternative with zero dependencies
  • UnionGenerator.OneOfSourceGen: Compile-time code generation (zero reflection)
  • OneOf: The OneOf library this extends

📄 License

MIT (same as UnionGenerator repository)


✨ Summary

Feature Benefit
Fluent API Natural, readable syntax
Extension Methods Works with LINQ seamlessly
JSON Support Built-in serialization
Fast Performance ~10-35 µs per conversion
OneOf v3 Native Modern library support

Use when: You're using OneOf v3 and want fluent conversion to UnionGenerator types with JSON support. For minimal dependencies, use OneOfCompat instead. 🚀

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 95 1/21/2026

Initial release: Fluent extension methods for OneOf to UnionGenerator conversion with JSON support.