UnionGenerator.OneOfExtensions
0.1.0
dotnet add package UnionGenerator.OneOfExtensions --version 0.1.0
NuGet\Install-Package UnionGenerator.OneOfExtensions -Version 0.1.0
<PackageReference Include="UnionGenerator.OneOfExtensions" Version="0.1.0" />
<PackageVersion Include="UnionGenerator.OneOfExtensions" Version="0.1.0" />
<PackageReference Include="UnionGenerator.OneOfExtensions" />
paket add UnionGenerator.OneOfExtensions --version 0.1.0
#r "nuget: UnionGenerator.OneOfExtensions, 0.1.0"
#:package UnionGenerator.OneOfExtensions@0.1.0
#addin nuget:?package=UnionGenerator.OneOfExtensions&version=0.1.0
#tool nuget:?package=UnionGenerator.OneOfExtensions&version=0.1.0
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:
- Extension method on
OneOf<T0, T1> - Uses reflection to detect which case is active
- Calls appropriate factory method:
Ok(T0)orError(T1) - 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
- Cache the extension result if converting many times:
var converter = oneOfValue.ToGeneratedResult<...>(); // Reuse converter multiple times - Use pattern matching in hot paths instead of repeated conversions
- Batch operations to amortize reflection cost
- 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:
- Ensure
using UnionGenerator.OneOfExtensions;is present - Check package is installed:
dotnet list package | grep OneOfExtensions - Rebuild project:
dotnet clean && dotnet build - 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:
- Ensure Newtonsoft.Json v13+ is installed
- OneOf library must also be installed and compatible
- Check JsonSerializerSettings if using custom converters
- Verify union types are JSON-serializable
Case Detection Error
Problem: Wrong case detected during conversion
Solution:
- Verify
OneOf<T0, T1>case is set correctly before conversion - Use
.IsT0or.IsT1properties to verify state - Check factory method names match ("Ok", "Error")
- 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
🔗 Related Packages
- 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 | Versions 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. |
-
net8.0
- Newtonsoft.Json (>= 13.0.3)
- OneOf (>= 3.0.271)
- UnionGenerator (>= 0.1.0)
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.