diff --git a/apiCount.include.md b/apiCount.include.md
index 1d791631..1b6bbe5a 100644
--- a/apiCount.include.md
+++ b/apiCount.include.md
@@ -1,28 +1,28 @@
-**API count: 1032**
+**API count: 1034**
### Per Target Framework
| Target | APIs |
| -- | -- |
-| `net461` | 974 |
-| `net462` | 974 |
-| `net47` | 973 |
-| `net471` | 972 |
-| `net472` | 968 |
-| `net48` | 968 |
-| `net481` | 968 |
-| `netstandard2.0` | 970 |
-| `netstandard2.1` | 823 |
-| `netcoreapp2.0` | 893 |
-| `netcoreapp2.1` | 834 |
-| `netcoreapp2.2` | 834 |
-| `netcoreapp3.0` | 786 |
-| `netcoreapp3.1` | 785 |
-| `net5.0` | 657 |
-| `net6.0` | 558 |
-| `net7.0` | 403 |
-| `net8.0` | 284 |
-| `net9.0` | 190 |
-| `net10.0` | 136 |
+| `net461` | 976 |
+| `net462` | 976 |
+| `net47` | 975 |
+| `net471` | 974 |
+| `net472` | 970 |
+| `net48` | 970 |
+| `net481` | 970 |
+| `netstandard2.0` | 972 |
+| `netstandard2.1` | 825 |
+| `netcoreapp2.0` | 895 |
+| `netcoreapp2.1` | 836 |
+| `netcoreapp2.2` | 836 |
+| `netcoreapp3.0` | 788 |
+| `netcoreapp3.1` | 787 |
+| `net5.0` | 659 |
+| `net6.0` | 560 |
+| `net7.0` | 405 |
+| `net8.0` | 286 |
+| `net9.0` | 192 |
+| `net10.0` | 138 |
| `net11.0` | 58 |
-| `uap10.0` | 960 |
+| `uap10.0` | 962 |
diff --git a/api_list.include.md b/api_list.include.md
index 6bf1aa6d..3c1a6ec2 100644
--- a/api_list.include.md
+++ b/api_list.include.md
@@ -1531,6 +1531,8 @@
#### UnreachableException
+#### IUnion
+
#### StringStream
#### ReadOnlyMemoryStream
diff --git a/assemblySize.include.md b/assemblySize.include.md
index 339ab210..a0a8d92e 100644
--- a/assemblySize.include.md
+++ b/assemblySize.include.md
@@ -2,51 +2,51 @@
| | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability |
|----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 | 8.0KB | 358.5KB | +350.5KB | +8.0KB | +6.5KB | +8.0KB | +12.5KB |
-| netstandard2.1 | 8.5KB | 312.5KB | +304.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB |
-| net461 | 8.5KB | 357.5KB | +349.0KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
-| net462 | 7.0KB | 361.0KB | +354.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
-| net47 | 7.0KB | 360.5KB | +353.5KB | +9.5KB | +6.5KB | +9.5KB | +14.0KB |
-| net471 | 8.5KB | 360.0KB | +351.5KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
-| net472 | 8.5KB | 358.5KB | +350.0KB | +7.5KB | +6.5KB | +8.0KB | +12.0KB |
-| net48 | 8.5KB | 358.5KB | +350.0KB | +7.5KB | +6.5KB | +8.0KB | +12.0KB |
-| net481 | 8.5KB | 358.5KB | +350.0KB | +7.5KB | +6.5KB | +8.0KB | +12.0KB |
-| netcoreapp2.0 | 9.0KB | 336.0KB | +327.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
-| netcoreapp2.1 | 9.0KB | 316.0KB | +307.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB |
-| netcoreapp2.2 | 9.0KB | 316.0KB | +307.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB |
-| netcoreapp3.0 | 9.5KB | 309.5KB | +300.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
-| netcoreapp3.1 | 9.5KB | 307.5KB | +298.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB |
-| net5.0 | 9.5KB | 271.5KB | +262.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB |
-| net6.0 | 10.0KB | 213.0KB | +203.0KB | +9.5KB | +7.0KB | +512bytes | +3.5KB |
-| net7.0 | 10.0KB | 175.0KB | +165.0KB | +11.5KB | +8.0KB | +512bytes | +3.0KB |
-| net8.0 | 9.5KB | 145.5KB | +136.0KB | +8.0KB | | +512bytes | +3.0KB |
-| net9.0 | 9.5KB | 98.5KB | +89.0KB | +8.5KB | | +512bytes | +3.0KB |
-| net10.0 | 10.0KB | 76.0KB | +66.0KB | +8.5KB | | +512bytes | +3.5KB |
-| net11.0 | 10.0KB | 20.5KB | +10.5KB | +9.0KB | | +1.0KB | +3.5KB |
+| netstandard2.0 | 8.0KB | 359.0KB | +351.0KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
+| netstandard2.1 | 8.5KB | 313.0KB | +304.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net461 | 8.5KB | 357.5KB | +349.0KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
+| net462 | 7.0KB | 361.0KB | +354.0KB | +9.5KB | +6.5KB | +9.5KB | +14.0KB |
+| net47 | 7.0KB | 361.0KB | +354.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net471 | 8.5KB | 360.0KB | +351.5KB | +7.5KB | +6.5KB | +8.0KB | +12.5KB |
+| net472 | 8.5KB | 358.5KB | +350.0KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
+| net48 | 8.5KB | 358.5KB | +350.0KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
+| net481 | 8.5KB | 359.0KB | +350.5KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
+| netcoreapp2.0 | 9.0KB | 336.5KB | +327.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| netcoreapp2.1 | 9.0KB | 316.5KB | +307.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| netcoreapp2.2 | 9.0KB | 316.5KB | +307.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| netcoreapp3.0 | 9.5KB | 309.5KB | +300.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB |
+| netcoreapp3.1 | 9.5KB | 308.0KB | +298.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net5.0 | 9.5KB | 272.0KB | +262.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net6.0 | 10.0KB | 213.0KB | +203.0KB | +10.0KB | +7.0KB | +1.0KB | +3.5KB |
+| net7.0 | 10.0KB | 175.0KB | +165.0KB | +12.0KB | +8.5KB | +512bytes | +3.5KB |
+| net8.0 | 9.5KB | 145.5KB | +136.0KB | +8.5KB | +512bytes | +512bytes | +3.5KB |
+| net9.0 | 9.5KB | 98.5KB | +89.0KB | +8.5KB | | +512bytes | +3.5KB |
+| net10.0 | 10.0KB | 76.0KB | +66.0KB | +9.0KB | | +1.0KB | +3.5KB |
+| net11.0 | 10.0KB | 21.0KB | +11.0KB | +9.0KB | | +512bytes | +3.5KB |
### Assembly Sizes with EmbedUntrackedSources
| | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability |
|----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 | 8.0KB | 525.1KB | +517.1KB | +15.7KB | +8.2KB | +12.9KB | +17.9KB |
-| netstandard2.1 | 8.5KB | 452.5KB | +444.0KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB |
-| net461 | 8.5KB | 525.2KB | +516.7KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
-| net462 | 7.0KB | 528.7KB | +521.7KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
-| net47 | 7.0KB | 527.9KB | +520.9KB | +17.2KB | +8.2KB | +14.4KB | +19.4KB |
-| net471 | 8.5KB | 527.1KB | +518.6KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
-| net472 | 8.5KB | 524.5KB | +516.0KB | +15.2KB | +8.2KB | +12.9KB | +17.4KB |
-| net48 | 8.5KB | 524.5KB | +516.0KB | +15.2KB | +8.2KB | +12.9KB | +17.4KB |
-| net481 | 8.5KB | 524.5KB | +516.0KB | +15.2KB | +8.2KB | +12.9KB | +17.4KB |
-| netcoreapp2.0 | 9.0KB | 492.1KB | +483.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
-| netcoreapp2.1 | 9.0KB | 459.7KB | +450.7KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB |
-| netcoreapp2.2 | 9.0KB | 459.7KB | +450.7KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB |
-| netcoreapp3.0 | 9.5KB | 444.3KB | +434.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
-| netcoreapp3.1 | 9.5KB | 442.3KB | +432.8KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB |
-| net5.0 | 9.5KB | 388.1KB | +378.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB |
-| net6.0 | 10.0KB | 309.4KB | +299.4KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB |
-| net7.0 | 10.0KB | 252.6KB | +242.6KB | +19.1KB | +9.4KB | +1.1KB | +3.7KB |
-| net8.0 | 9.5KB | 207.6KB | +198.1KB | +15.5KB | +299bytes | +1.1KB | +3.7KB |
-| net9.0 | 9.5KB | 139.5KB | +130.0KB | +16.0KB | | +1.1KB | +3.7KB |
-| net10.0 | 10.0KB | 108.3KB | +98.3KB | +16.0KB | | +1.1KB | +4.2KB |
-| net11.0 | 10.0KB | 30.4KB | +20.4KB | +16.5KB | | +1.6KB | +4.2KB |
+| netstandard2.0 | 8.0KB | 526.3KB | +518.3KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
+| netstandard2.1 | 8.5KB | 453.6KB | +445.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net461 | 8.5KB | 525.8KB | +517.3KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
+| net462 | 7.0KB | 529.3KB | +522.3KB | +17.2KB | +8.2KB | +14.4KB | +19.4KB |
+| net47 | 7.0KB | 529.1KB | +522.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net471 | 8.5KB | 527.7KB | +519.2KB | +15.2KB | +8.2KB | +12.9KB | +17.9KB |
+| net472 | 8.5KB | 525.1KB | +516.6KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
+| net48 | 8.5KB | 525.1KB | +516.6KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
+| net481 | 8.5KB | 525.6KB | +517.1KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
+| netcoreapp2.0 | 9.0KB | 493.2KB | +484.2KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| netcoreapp2.1 | 9.0KB | 460.9KB | +451.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| netcoreapp2.2 | 9.0KB | 460.9KB | +451.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| netcoreapp3.0 | 9.5KB | 445.0KB | +435.5KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB |
+| netcoreapp3.1 | 9.5KB | 443.4KB | +433.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net5.0 | 9.5KB | 389.3KB | +379.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net6.0 | 10.0KB | 310.1KB | +300.1KB | +17.7KB | +8.7KB | +1.6KB | +4.2KB |
+| net7.0 | 10.0KB | 253.2KB | +243.2KB | +19.6KB | +9.9KB | +1.1KB | +4.2KB |
+| net8.0 | 9.5KB | 208.2KB | +198.7KB | +16.0KB | +811bytes | +1.1KB | +4.2KB |
+| net9.0 | 9.5KB | 140.1KB | +130.6KB | +16.0KB | | +1.1KB | +4.2KB |
+| net10.0 | 10.0KB | 108.9KB | +98.9KB | +16.5KB | | +1.6KB | +4.2KB |
+| net11.0 | 10.0KB | 30.9KB | +20.9KB | +16.5KB | | +1.1KB | +4.2KB |
diff --git a/readme.md b/readme.md
index 12efb593..ddf0baec 100644
--- a/readme.md
+++ b/readme.md
@@ -13,34 +13,34 @@ The package targets `netstandard2.0` and is designed to support the following ru
* `uap10`
-**API count: 1031**
+**API count: 1034**
### Per Target Framework
| Target | APIs |
| -- | -- |
-| `net461` | 973 |
-| `net462` | 973 |
-| `net47` | 972 |
-| `net471` | 971 |
-| `net472` | 967 |
-| `net48` | 967 |
-| `net481` | 967 |
-| `netstandard2.0` | 969 |
-| `netstandard2.1` | 822 |
-| `netcoreapp2.0` | 892 |
-| `netcoreapp2.1` | 833 |
-| `netcoreapp2.2` | 833 |
-| `netcoreapp3.0` | 785 |
-| `netcoreapp3.1` | 784 |
-| `net5.0` | 656 |
-| `net6.0` | 557 |
-| `net7.0` | 402 |
-| `net8.0` | 283 |
-| `net9.0` | 189 |
-| `net10.0` | 135 |
+| `net461` | 976 |
+| `net462` | 976 |
+| `net47` | 975 |
+| `net471` | 974 |
+| `net472` | 970 |
+| `net48` | 970 |
+| `net481` | 970 |
+| `netstandard2.0` | 972 |
+| `netstandard2.1` | 825 |
+| `netcoreapp2.0` | 895 |
+| `netcoreapp2.1` | 836 |
+| `netcoreapp2.2` | 836 |
+| `netcoreapp3.0` | 788 |
+| `netcoreapp3.1` | 787 |
+| `net5.0` | 659 |
+| `net6.0` | 560 |
+| `net7.0` | 405 |
+| `net8.0` | 286 |
+| `net9.0` | 192 |
+| `net10.0` | 138 |
| `net11.0` | 58 |
-| `uap10.0` | 959 |
+| `uap10.0` | 962 |
@@ -96,54 +96,54 @@ This project uses features from the newest stable SDK and C# language. As such c
| | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability |
|----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 | 8.0KB | 358.5KB | +350.5KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
-| netstandard2.1 | 8.5KB | 313.0KB | +304.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB |
-| net461 | 8.5KB | 357.5KB | +349.0KB | +7.5KB | +6.5KB | +8.0KB | +12.0KB |
-| net462 | 7.0KB | 361.0KB | +354.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
-| net47 | 7.0KB | 361.0KB | +354.0KB | +9.0KB | +6.0KB | +9.0KB | +13.5KB |
-| net471 | 8.5KB | 360.0KB | +351.5KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
-| net472 | 8.5KB | 358.5KB | +350.0KB | +7.5KB | +6.5KB | +8.0KB | +12.5KB |
-| net48 | 8.5KB | 358.5KB | +350.0KB | +7.5KB | +6.5KB | +8.0KB | +12.5KB |
-| net481 | 8.5KB | 358.5KB | +350.0KB | +8.0KB | +6.5KB | +8.0KB | +12.5KB |
-| netcoreapp2.0 | 9.0KB | 336.5KB | +327.5KB | +8.5KB | +6.0KB | +8.5KB | +13.5KB |
-| netcoreapp2.1 | 9.0KB | 316.5KB | +307.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB |
+| netstandard2.0 | 8.0KB | 359.0KB | +351.0KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
+| netstandard2.1 | 8.5KB | 313.0KB | +304.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net461 | 8.5KB | 357.5KB | +349.0KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
+| net462 | 7.0KB | 361.0KB | +354.0KB | +9.5KB | +6.5KB | +9.5KB | +14.0KB |
+| net47 | 7.0KB | 361.0KB | +354.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net471 | 8.5KB | 360.0KB | +351.5KB | +7.5KB | +6.5KB | +8.0KB | +12.5KB |
+| net472 | 8.5KB | 358.5KB | +350.0KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
+| net48 | 8.5KB | 358.5KB | +350.0KB | +8.0KB | +7.0KB | +8.0KB | +12.5KB |
+| net481 | 8.5KB | 359.0KB | +350.5KB | +7.5KB | +6.5KB | +7.5KB | +12.0KB |
+| netcoreapp2.0 | 9.0KB | 336.5KB | +327.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| netcoreapp2.1 | 9.0KB | 316.5KB | +307.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
| netcoreapp2.2 | 9.0KB | 316.5KB | +307.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
-| netcoreapp3.0 | 9.5KB | 309.5KB | +300.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
-| netcoreapp3.1 | 9.5KB | 308.0KB | +298.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB |
-| net5.0 | 9.5KB | 272.0KB | +262.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB |
-| net6.0 | 10.0KB | 213.0KB | +203.0KB | +10.0KB | +7.0KB | +512bytes | +3.5KB |
-| net7.0 | 10.0KB | 175.0KB | +165.0KB | +11.5KB | +8.0KB | +512bytes | +3.0KB |
-| net8.0 | 9.5KB | 145.5KB | +136.0KB | +8.5KB | | +512bytes | +3.0KB |
+| netcoreapp3.0 | 9.5KB | 309.5KB | +300.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB |
+| netcoreapp3.1 | 9.5KB | 308.0KB | +298.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net5.0 | 9.5KB | 272.0KB | +262.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB |
+| net6.0 | 10.0KB | 213.0KB | +203.0KB | +10.0KB | +7.0KB | +1.0KB | +3.5KB |
+| net7.0 | 10.0KB | 175.0KB | +165.0KB | +12.0KB | +8.5KB | +512bytes | +3.5KB |
+| net8.0 | 9.5KB | 145.5KB | +136.0KB | +8.5KB | +512bytes | +512bytes | +3.5KB |
| net9.0 | 9.5KB | 98.5KB | +89.0KB | +8.5KB | | +512bytes | +3.5KB |
-| net10.0 | 10.0KB | 76.0KB | +66.0KB | +8.5KB | | +512bytes | +3.5KB |
-| net11.0 | 10.0KB | 20.5KB | +10.5KB | +9.0KB | | +1.0KB | +3.5KB |
+| net10.0 | 10.0KB | 76.0KB | +66.0KB | +9.0KB | | +1.0KB | +3.5KB |
+| net11.0 | 10.0KB | 21.0KB | +11.0KB | +9.0KB | | +512bytes | +3.5KB |
### Assembly Sizes with EmbedUntrackedSources
| | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability |
|----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 | 8.0KB | 524.8KB | +516.8KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
-| netstandard2.1 | 8.5KB | 452.7KB | +444.2KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB |
-| net461 | 8.5KB | 524.9KB | +516.4KB | +15.2KB | +8.2KB | +12.9KB | +17.4KB |
-| net462 | 7.0KB | 528.4KB | +521.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
-| net47 | 7.0KB | 528.1KB | +521.1KB | +16.7KB | +7.7KB | +13.9KB | +18.9KB |
-| net471 | 8.5KB | 526.8KB | +518.3KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
-| net472 | 8.5KB | 524.2KB | +515.7KB | +15.2KB | +8.2KB | +12.9KB | +17.9KB |
-| net48 | 8.5KB | 524.2KB | +515.7KB | +15.2KB | +8.2KB | +12.9KB | +17.9KB |
-| net481 | 8.5KB | 524.2KB | +515.7KB | +15.7KB | +8.2KB | +12.9KB | +17.9KB |
-| netcoreapp2.0 | 9.0KB | 492.3KB | +483.3KB | +16.2KB | +7.7KB | +13.4KB | +18.9KB |
-| netcoreapp2.1 | 9.0KB | 459.9KB | +450.9KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB |
-| netcoreapp2.2 | 9.0KB | 459.9KB | +450.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
-| netcoreapp3.0 | 9.5KB | 444.0KB | +434.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
-| netcoreapp3.1 | 9.5KB | 442.5KB | +433.0KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB |
-| net5.0 | 9.5KB | 388.3KB | +378.8KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB |
-| net6.0 | 10.0KB | 309.1KB | +299.1KB | +17.7KB | +8.7KB | +1.1KB | +4.2KB |
-| net7.0 | 10.0KB | 252.3KB | +242.3KB | +19.1KB | +9.4KB | +1.1KB | +3.7KB |
-| net8.0 | 9.5KB | 207.3KB | +197.8KB | +16.0KB | +299bytes | +1.1KB | +3.7KB |
-| net9.0 | 9.5KB | 139.1KB | +129.6KB | +16.0KB | | +1.1KB | +4.2KB |
-| net10.0 | 10.0KB | 108.0KB | +98.0KB | +16.0KB | | +1.1KB | +4.2KB |
-| net11.0 | 10.0KB | 30.4KB | +20.4KB | +16.5KB | | +1.6KB | +4.2KB |
+| netstandard2.0 | 8.0KB | 526.3KB | +518.3KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
+| netstandard2.1 | 8.5KB | 453.6KB | +445.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net461 | 8.5KB | 525.8KB | +517.3KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
+| net462 | 7.0KB | 529.3KB | +522.3KB | +17.2KB | +8.2KB | +14.4KB | +19.4KB |
+| net47 | 7.0KB | 529.1KB | +522.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net471 | 8.5KB | 527.7KB | +519.2KB | +15.2KB | +8.2KB | +12.9KB | +17.9KB |
+| net472 | 8.5KB | 525.1KB | +516.6KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
+| net48 | 8.5KB | 525.1KB | +516.6KB | +15.7KB | +8.7KB | +12.9KB | +17.9KB |
+| net481 | 8.5KB | 525.6KB | +517.1KB | +15.2KB | +8.2KB | +12.4KB | +17.4KB |
+| netcoreapp2.0 | 9.0KB | 493.2KB | +484.2KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| netcoreapp2.1 | 9.0KB | 460.9KB | +451.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| netcoreapp2.2 | 9.0KB | 460.9KB | +451.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| netcoreapp3.0 | 9.5KB | 445.0KB | +435.5KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB |
+| netcoreapp3.1 | 9.5KB | 443.4KB | +433.9KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net5.0 | 9.5KB | 389.3KB | +379.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB |
+| net6.0 | 10.0KB | 310.1KB | +300.1KB | +17.7KB | +8.7KB | +1.6KB | +4.2KB |
+| net7.0 | 10.0KB | 253.2KB | +243.2KB | +19.6KB | +9.9KB | +1.1KB | +4.2KB |
+| net8.0 | 9.5KB | 208.2KB | +198.7KB | +16.0KB | +811bytes | +1.1KB | +4.2KB |
+| net9.0 | 9.5KB | 140.1KB | +130.6KB | +16.0KB | | +1.1KB | +4.2KB |
+| net10.0 | 10.0KB | 108.9KB | +98.9KB | +16.5KB | | +1.6KB | +4.2KB |
+| net11.0 | 10.0KB | 30.9KB | +20.9KB | +16.5KB | | +1.1KB | +4.2KB |
@@ -524,6 +524,90 @@ Reference: [Improvements in native code interop in .NET 5.0](https://devblogs.mi
* [DisableRuntimeMarshallingAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.disableruntimemarshallingattribute)
+### Unions
+
+Polyfills the two marker types that the compiler references when emitting [C# 15 union types](https://devblogs.microsoft.com/dotnet/csharp-15-union-types/), so unions can target older runtimes:
+
+ * [UnionAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.unionattribute)
+ * [IUnion](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.iunion)
+
+Both types ship in net11. Without them the compiler rejects a `union` declaration with `CS0518` and `CS0656`, so Polyfill supplies them on every earlier target.
+
+> Polyfill supplies only the `UnionAttribute` and `IUnion` types that the generated union struct references. The `union` keyword itself requires the C# 15 (or later) compiler and cannot be backported to an older compiler. Set `preview` while the feature is in preview.
+
+> If the consuming project declares its own `UnionAttribute`/`IUnion` in `System.Runtime.CompilerServices` (as preview guidance suggested before these types shipped), delete those declarations. Keeping them results in `CS0101` on earlier targets and `CS0729` on net11.
+
+Declaring a union:
+
+
+
+```cs
+record Cat(string Name);
+
+record Dog(string Name);
+
+record Bird(string Name);
+
+union Pet(Cat, Dog, Bird);
+```
+snippet source | anchor
+
+
+Consuming a union, using the implicit conversion from a case type and pattern matching to unwrap it:
+
+
+
+```cs
+public static string Describe(Dog dog)
+{
+ // implicit conversion from one of the case types
+ Pet pet = dog;
+
+ // no default arm: the switch is exhaustive because every case type is handled
+ return pet switch
+ {
+ Cat cat => $"cat {cat.Name}",
+ Dog other => $"dog {other.Name}",
+ Bird bird => $"bird {bird.Name}"
+ };
+}
+```
+snippet source | anchor
+
+
+The generated union struct implements `IUnion`, so the current value can also be read as an `object`:
+
+
+
+```cs
+// every union implements IUnion, which exposes the current value as object
+public static object? CurrentValue(Pet pet) =>
+ ((IUnion) pet).Value;
+```
+snippet source | anchor
+
+
+A union can also be declared explicitly using the polyfilled attribute and interface:
+
+
+
+```cs
+[Union]
+readonly struct IntOrString : IUnion
+{
+ readonly object? value;
+
+ public IntOrString(int value) => this.value = value;
+
+ public IntOrString(string value) => this.value = value;
+
+ public object? Value => value;
+}
+```
+snippet source | anchor
+
+
+
## Extensions
The class `Polyfill` includes the following extension methods:
@@ -2062,6 +2146,8 @@ The class `Polyfill` includes the following extension methods:
#### UnreachableException
+#### IUnion
+
#### StringStream
#### ReadOnlyMemoryStream
@@ -2267,7 +2353,7 @@ void ObjectDisposedExceptionExample(bool isDisposed)
ObjectDisposedException.ThrowIf(isDisposed, typeof(Consume));
}
```
-snippet source | anchor
+snippet source | anchor
@@ -2286,7 +2372,7 @@ void EnsureExample(Order order, Customer customer, string customerId, string ema
this.quantity = Ensure.NotNegativeOrZero(quantity);
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/src/ApiBuilderTests/BuildApiTest.cs b/src/ApiBuilderTests/BuildApiTest.cs
index 42fc1098..b5ab6928 100644
--- a/src/ApiBuilderTests/BuildApiTest.cs
+++ b/src/ApiBuilderTests/BuildApiTest.cs
@@ -24,6 +24,7 @@ public Task RunWithRoslyn()
WriteHelper("Utf16", writer, ref count);
WriteType(nameof(TaskCompletionSource), writer, ref count);
WriteType(nameof(UnreachableException), writer, ref count);
+ WriteType("IUnion", writer, ref count);
WriteType("StringStream", writer, ref count);
WriteType("ReadOnlyMemoryStream", writer, ref count);
WriteType("WritableMemoryStream", writer, ref count);
diff --git a/src/Consume/Consume.cs b/src/Consume/Consume.cs
index 868deba1..8e9a5870 100644
--- a/src/Consume/Consume.cs
+++ b/src/Consume/Consume.cs
@@ -104,6 +104,8 @@ class Consume
type = typeof(RequiresUnreferencedCodeAttribute);
type = typeof(UnconditionalSuppressMessageAttribute);
type = typeof(CompilerFeatureRequiredAttribute);
+ type = typeof(IUnion);
+ type = typeof(UnionAttribute);
#if FeatureMemory
type = typeof(CollectionBuilderAttribute);
#endif
diff --git a/src/ConsumeCsPreview/Unions.cs b/src/ConsumeCsPreview/Unions.cs
new file mode 100644
index 00000000..5d44611c
--- /dev/null
+++ b/src/ConsumeCsPreview/Unions.cs
@@ -0,0 +1,48 @@
+using System.Runtime.CompilerServices;
+
+namespace ConsumeCsPreview;
+
+// Compile-only coverage for C# union types. The compiler emits a struct that is
+// annotated with UnionAttribute and implements IUnion, so this only compiles
+// when both are polyfilled.
+
+#region UnionDeclaration
+
+record Cat(string Name);
+
+record Dog(string Name);
+
+record Bird(string Name);
+
+union Pet(Cat, Dog, Bird);
+
+#endregion
+
+static class Unions
+{
+ #region UnionUsage
+
+ public static string Describe(Dog dog)
+ {
+ // implicit conversion from one of the case types
+ Pet pet = dog;
+
+ // no default arm: the switch is exhaustive because every case type is handled
+ return pet switch
+ {
+ Cat cat => $"cat {cat.Name}",
+ Dog other => $"dog {other.Name}",
+ Bird bird => $"bird {bird.Name}"
+ };
+ }
+
+ #endregion
+
+ #region UnionValue
+
+ // every union implements IUnion, which exposes the current value as object
+ public static object? CurrentValue(Pet pet) =>
+ ((IUnion) pet).Value;
+
+ #endregion
+}
diff --git a/src/Polyfill/IUnion.cs b/src/Polyfill/IUnion.cs
new file mode 100644
index 00000000..fbc4dcd7
--- /dev/null
+++ b/src/Polyfill/IUnion.cs
@@ -0,0 +1,26 @@
+#if !NET11_0_OR_GREATER
+#nullable enable
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+//Link: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.iunion?view=net-11.0
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
+
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.IUnion))]
+#endif
diff --git a/src/Polyfill/UnionAttribute.cs b/src/Polyfill/UnionAttribute.cs
new file mode 100644
index 00000000..aeecb2b5
--- /dev/null
+++ b/src/Polyfill/UnionAttribute.cs
@@ -0,0 +1,25 @@
+#if !NET11_0_OR_GREATER
+
+namespace System.Runtime.CompilerServices;
+
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+//Link: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.unionattribute?view=net-11.0
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
+
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.UnionAttribute))]
+#endif
diff --git a/src/Split/net10.0/IUnion.cs b/src/Split/net10.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net10.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net10.0/UnionAttribute.cs b/src/Split/net10.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net10.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net11.0/TypeForwardeds.cs b/src/Split/net11.0/TypeForwardeds.cs
index 435914d1..5b038c2e 100644
--- a/src/Split/net11.0/TypeForwardeds.cs
+++ b/src/Split/net11.0/TypeForwardeds.cs
@@ -20,6 +20,7 @@
[assembly: TypeForwardedTo(typeof(System.Collections.Generic.IAlternateEqualityComparer<,>))]
[assembly: TypeForwardedTo(typeof(System.Runtime.CompilerServices.IsClosedTypeAttribute))]
[assembly: TypeForwardedTo(typeof(System.Runtime.CompilerServices.IsExternalInit))]
+[assembly: TypeForwardedTo(typeof(System.Runtime.CompilerServices.IUnion))]
[assembly: TypeForwardedTo(typeof(System.Collections.Generic.KeyValuePair))]
[assembly: TypeForwardedTo(typeof(System.Threading.Lock))]
[assembly: TypeForwardedTo(typeof(System.IO.MatchCasing))]
@@ -44,6 +45,7 @@
[assembly: TypeForwardedTo(typeof(System.IO.StringStream))]
[assembly: TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute))]
[assembly: TypeForwardedTo(typeof(System.Runtime.InteropServices.SuppressGCTransitionAttribute))]
+[assembly: TypeForwardedTo(typeof(System.Runtime.CompilerServices.UnionAttribute))]
[assembly: TypeForwardedTo(typeof(System.IO.UnixFileMode))]
[assembly: TypeForwardedTo(typeof(System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute))]
[assembly: TypeForwardedTo(typeof(System.Diagnostics.UnreachableException))]
diff --git a/src/Split/net461/IUnion.cs b/src/Split/net461/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net461/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net461/UnionAttribute.cs b/src/Split/net461/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net461/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net462/IUnion.cs b/src/Split/net462/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net462/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net462/UnionAttribute.cs b/src/Split/net462/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net462/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net47/IUnion.cs b/src/Split/net47/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net47/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net47/UnionAttribute.cs b/src/Split/net47/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net47/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net471/IUnion.cs b/src/Split/net471/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net471/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net471/UnionAttribute.cs b/src/Split/net471/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net471/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net472/IUnion.cs b/src/Split/net472/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net472/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net472/UnionAttribute.cs b/src/Split/net472/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net472/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net48/IUnion.cs b/src/Split/net48/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net48/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net48/UnionAttribute.cs b/src/Split/net48/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net48/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net481/IUnion.cs b/src/Split/net481/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net481/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net481/UnionAttribute.cs b/src/Split/net481/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net481/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net5.0/IUnion.cs b/src/Split/net5.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net5.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net5.0/UnionAttribute.cs b/src/Split/net5.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net5.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net6.0/IUnion.cs b/src/Split/net6.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net6.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net6.0/UnionAttribute.cs b/src/Split/net6.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net6.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net7.0/IUnion.cs b/src/Split/net7.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net7.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net7.0/UnionAttribute.cs b/src/Split/net7.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net7.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net8.0/IUnion.cs b/src/Split/net8.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net8.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net8.0/UnionAttribute.cs b/src/Split/net8.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net8.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/net9.0/IUnion.cs b/src/Split/net9.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/net9.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/net9.0/UnionAttribute.cs b/src/Split/net9.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/net9.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netcoreapp2.0/IUnion.cs b/src/Split/netcoreapp2.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netcoreapp2.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netcoreapp2.0/UnionAttribute.cs b/src/Split/netcoreapp2.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netcoreapp2.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netcoreapp2.1/IUnion.cs b/src/Split/netcoreapp2.1/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netcoreapp2.1/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netcoreapp2.1/UnionAttribute.cs b/src/Split/netcoreapp2.1/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netcoreapp2.1/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netcoreapp2.2/IUnion.cs b/src/Split/netcoreapp2.2/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netcoreapp2.2/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netcoreapp2.2/UnionAttribute.cs b/src/Split/netcoreapp2.2/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netcoreapp2.2/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netcoreapp3.0/IUnion.cs b/src/Split/netcoreapp3.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netcoreapp3.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netcoreapp3.0/UnionAttribute.cs b/src/Split/netcoreapp3.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netcoreapp3.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netcoreapp3.1/IUnion.cs b/src/Split/netcoreapp3.1/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netcoreapp3.1/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netcoreapp3.1/UnionAttribute.cs b/src/Split/netcoreapp3.1/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netcoreapp3.1/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netstandard2.0/IUnion.cs b/src/Split/netstandard2.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netstandard2.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netstandard2.0/UnionAttribute.cs b/src/Split/netstandard2.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netstandard2.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/netstandard2.1/IUnion.cs b/src/Split/netstandard2.1/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/netstandard2.1/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/netstandard2.1/UnionAttribute.cs b/src/Split/netstandard2.1/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/netstandard2.1/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Split/uap10.0/IUnion.cs b/src/Split/uap10.0/IUnion.cs
new file mode 100644
index 00000000..1a5691a4
--- /dev/null
+++ b/src/Split/uap10.0/IUnion.cs
@@ -0,0 +1,20 @@
+//
+#pragma warning disable
+#nullable enable
+namespace System.Runtime.CompilerServices;
+///
+/// Provides a common interface for accessing the contents of a union type at runtime.
+///
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+interface IUnion
+{
+ ///
+ /// Gets the value contained in the union, or if the union has no value.
+ ///
+ object? Value { get; }
+}
diff --git a/src/Split/uap10.0/UnionAttribute.cs b/src/Split/uap10.0/UnionAttribute.cs
new file mode 100644
index 00000000..6f79f10e
--- /dev/null
+++ b/src/Split/uap10.0/UnionAttribute.cs
@@ -0,0 +1,18 @@
+//
+#pragma warning disable
+namespace System.Runtime.CompilerServices;
+using Diagnostics;
+using Diagnostics.CodeAnalysis;
+///
+/// Indicates that a class or struct is a union type, enabling compiler support for union behaviors.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class UnionAttribute : Attribute;
diff --git a/src/Tests/UnionTests.cs b/src/Tests/UnionTests.cs
new file mode 100644
index 00000000..309b8cf9
--- /dev/null
+++ b/src/Tests/UnionTests.cs
@@ -0,0 +1,67 @@
+using System.Reflection;
+
+public class UnionTests
+{
+ [Test]
+ public async Task IUnion_IsInterfaceExposingObjectValue()
+ {
+ var type = typeof(IUnion);
+ await Assert.That(type.IsInterface).IsTrue();
+
+ var property = type.GetProperty("Value");
+ await Assert.That(property).IsNotNull();
+ await Assert.That(property!.PropertyType).IsEqualTo(typeof(object));
+ }
+
+ [Test]
+ public async Task UnionAttribute_HasExpectedShape()
+ {
+ var type = typeof(UnionAttribute);
+ await Assert.That(type.IsSealed).IsTrue();
+ await Assert.That(typeof(Attribute).IsAssignableFrom(type)).IsTrue();
+
+ var usage = type.GetCustomAttribute();
+ await Assert.That(usage).IsNotNull();
+ await Assert.That(usage!.ValidOn).IsEqualTo(AttributeTargets.Class | AttributeTargets.Struct);
+ await Assert.That(usage.AllowMultiple).IsFalse();
+ await Assert.That(usage.Inherited).IsFalse();
+ }
+
+ [Test]
+ public async Task UserDefinedUnion_ValueRoundTrips()
+ {
+ IUnion fromInt = new IntOrString(5);
+ IUnion fromText = new IntOrString("text");
+
+ var intValue = fromInt.Value;
+ var textValue = fromText.Value;
+
+ await Assert.That(intValue).IsEqualTo(5);
+ await Assert.That(textValue).IsEqualTo("text");
+ }
+
+ [Test]
+ public async Task UserDefinedUnion_IsMarkedAndImplementsIUnion()
+ {
+ var type = typeof(IntOrString);
+
+ await Assert.That(type.GetCustomAttribute()).IsNotNull();
+ await Assert.That(typeof(IUnion).IsAssignableFrom(type)).IsTrue();
+ }
+
+ #region UnionExplicit
+
+ [Union]
+ readonly struct IntOrString : IUnion
+ {
+ readonly object? value;
+
+ public IntOrString(int value) => this.value = value;
+
+ public IntOrString(string value) => this.value = value;
+
+ public object? Value => value;
+ }
+
+ #endregion
+}