YayaInk.Orleans.Unions 0.1.0-preview.5

This is a prerelease version of YayaInk.Orleans.Unions.
dotnet add package YayaInk.Orleans.Unions --version 0.1.0-preview.5
                    
NuGet\Install-Package YayaInk.Orleans.Unions -Version 0.1.0-preview.5
                    
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="YayaInk.Orleans.Unions" Version="0.1.0-preview.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="YayaInk.Orleans.Unions" Version="0.1.0-preview.5" />
                    
Directory.Packages.props
<PackageReference Include="YayaInk.Orleans.Unions" />
                    
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 YayaInk.Orleans.Unions --version 0.1.0-preview.5
                    
#r "nuget: YayaInk.Orleans.Unions, 0.1.0-preview.5"
                    
#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 YayaInk.Orleans.Unions@0.1.0-preview.5
                    
#: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=YayaInk.Orleans.Unions&version=0.1.0-preview.5&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=YayaInk.Orleans.Unions&version=0.1.0-preview.5&prerelease
                    
Install as a Cake Tool

YayaInk.Orleans.Unions

ci NuGet NuGet License: MIT

Zero-boilerplate Microsoft Orleans serialization support for C# 15 union types (the union declaration introduced as a preview language feature).

Mark your union with [GenerateUnionSerializer] and the source generator emits a real Orleans IFieldCodec<T> and IDeepCopier<T> for it, plus the TypeManifestProvider registration that services.AddSerializer(b => b.AddAssembly(...)) needs to discover them.

Status: preview (0.1.x). API and wire format may still change before 1.0.

Packages

Package Purpose
YayaInk.Orleans.Unions Runtime marker attribute (GenerateUnionSerializerAttribute).
YayaInk.Orleans.Unions.Generators Roslyn source generator. Ships in analyzers/dotnet/cs/.

Install both into the project that declares your union types:

<ItemGroup>
  <PackageReference Include="YayaInk.Orleans.Unions" Version="0.1.0-preview.5" />
  <PackageReference Include="YayaInk.Orleans.Unions.Generators" Version="0.1.0-preview.5"
                    PrivateAssets="all" />
</ItemGroup>

Usage

using YayaInk.Orleans.Unions;

[Union]
[GenerateUnionSerializer]
public union Result<T>(Ok<T>, Err);

[GenerateSerializer] public sealed record Ok<T>([property: Id(0)] T Value);
[GenerateSerializer] public sealed record Err([property: Id(0)] string Message);

Then register the assembly with Orleans as usual:

services.AddSerializer(b => b.AddAssembly(typeof(Result<>).Assembly));

That's it — Result<T> will round-trip through Orleans codecs/copiers, work across silos, and compose inside other [GenerateSerializer] types.

Supported union shapes

Validated by the test suite:

  • Non-generic and generic unions (any arity)
  • Multiple cases (≥3) and forward-compatible unknown-tag fallback
  • record struct and record class cases
  • Inheritance-overlap cases (derived case stays derived after round-trip)
  • Nested unions (a union as a case payload, including multi-level)
  • Unions embedded in records, lists, dictionaries, and other Orleans messages
  • default / null IUnion.Value preservation

Performance notes

The union keyword always lowers to a struct wrapper containing a single object? Value field, regardless of the case types or generic constraints. That is the spec's design, not a temporary state — where T : struct does not trigger a different layout, and there is no compiler switch that makes union Foo(...) emit the unboxed byte _tag + per-case typed fields shape on its own.

What that means for this package:

  • The generator dispatches via ((IUnion)value).Value, which is the only shape the compiler produces for union declarations.
  • For value-type cases, the boxing happens inside the union's own constructor (new MyUnion(structValue)); the serializer does not add another layer of boxing on top of that.
  • CompilerShapeProbeTests simply pins this lowering as a regression guard; it is not a "waiting for the no-box form to land" probe.

The C# 15 spec does define a non-boxing access pattern, but only for hand-written [Union] struct types that opt in by implementing HasValue plus one or more bool TryGetValue(out T) overloads (see the "Non-boxing access pattern" section of the spec). The compiler then routes pattern matching through those typed accessors instead of Value.

This package currently targets the union keyword path only. Adding generator support for hand-written [Union] structs with TryGetValue overloads is a possible future enhancement and is independent of any compiler change.

Limitations

  • The C# union keyword is a preview language feature; you must enable LangVersion=preview and EnablePreviewFeatures=true in your project.
  • The package currently requires .NET SDK 11.0.100-preview.5.26302.115. This SDK supplies System.Runtime.CompilerServices.IUnion and UnionAttribute; consumers must not define or reference a polyfill for these runtime types.
  • Custom (handwritten) union layouts are out of scope; only the compiler-generated default form is supported.

License

MIT © YAYA-INK

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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.  net11.0 is compatible. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • net11.0

    • No dependencies.
  • net8.0

    • No dependencies.

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-preview.5 115 7/11/2026
0.1.0-preview.4 76 6/18/2026
0.1.0-preview.3 62 5/30/2026
0.1.0-preview.2 68 5/16/2026
0.1.0-preview.1 68 5/15/2026