YayaInk.Orleans.Unions
0.1.0-preview.5
dotnet add package YayaInk.Orleans.Unions --version 0.1.0-preview.5
NuGet\Install-Package YayaInk.Orleans.Unions -Version 0.1.0-preview.5
<PackageReference Include="YayaInk.Orleans.Unions" Version="0.1.0-preview.5" />
<PackageVersion Include="YayaInk.Orleans.Unions" Version="0.1.0-preview.5" />
<PackageReference Include="YayaInk.Orleans.Unions" />
paket add YayaInk.Orleans.Unions --version 0.1.0-preview.5
#r "nuget: YayaInk.Orleans.Unions, 0.1.0-preview.5"
#:package YayaInk.Orleans.Unions@0.1.0-preview.5
#addin nuget:?package=YayaInk.Orleans.Unions&version=0.1.0-preview.5&prerelease
#tool nuget:?package=YayaInk.Orleans.Unions&version=0.1.0-preview.5&prerelease
YayaInk.Orleans.Unions
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 structandrecord classcases- 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/ nullIUnion.Valuepreservation
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 foruniondeclarations. - 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. CompilerShapeProbeTestssimply 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#
unionkeyword is a preview language feature; you must enableLangVersion=previewandEnablePreviewFeatures=truein your project. - The package currently requires .NET SDK
11.0.100-preview.5.26302.115. This SDK suppliesSystem.Runtime.CompilerServices.IUnionandUnionAttribute; 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 | Versions 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. |
-
.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 |