MultiType.NET.Core
1.0.1
dotnet add package MultiType.NET.Core --version 1.0.1
NuGet\Install-Package MultiType.NET.Core -Version 1.0.1
<PackageReference Include="MultiType.NET.Core" Version="1.0.1" />
<PackageVersion Include="MultiType.NET.Core" Version="1.0.1" />
<PackageReference Include="MultiType.NET.Core" />
paket add MultiType.NET.Core --version 1.0.1
#r "nuget: MultiType.NET.Core, 1.0.1"
#:package MultiType.NET.Core@1.0.1
#addin nuget:?package=MultiType.NET.Core&version=1.0.1
#tool nuget:?package=MultiType.NET.Core&version=1.0.1
๐ฆ MultiType.NET
Type-safe, zero-allocation discriminated unions for modern .NET
Bring TypeScript-style union types to C# โ safer than object, cleaner than if, and built for real-world APIs and models.
Any<int, string> result = "hello";
๐ง What Is a Union Type?
A union type lets a value be one of multiple specified types โ like this in TypeScript:
let result = number | string | null
// C# with MultiType.NET
Any<int, string> result = "hello";
MultiType.NET brings that idea to C# with full support for:
- โ
Type-safe access (
Is<T>(),As<T>(),Match) - โ JSON (de)serialization
- โ Zero boxing
- โ ASP.NET API compatibility
- โ Source generation for no-boilerplate code
โจ Features Overview
| Category | Features |
|---|---|
| โ Matching | Match, TryMatch, Switch, SwitchAsync, SwitchOrDefault |
| ๐ Mapping | Map, MapAsync, MapSafe, MapValue, MapAny, MapWithContext, MapOrDefault, MapWhere |
| ๐ Selection | Select, TrySelect, SelectAsync, SelectAsyncOrDefault, SelectWithContext, SelectWhere |
| ๐ฆ Extraction | GetTn, TryGetTn, GetTn(out remainder), Deconstruct(...) |
| ๐ง Introspection | ActualType, AllowedTypes, IsNull, ToString() |
| โ๏ธ Construction | From, TryFrom, FromTn, implicit/explicit operators |
| ๐ค Serialization | Native System.Text.Json support (global or attribute-based) |
| ๐งโ๐ป API-Ready | Works with Controllers & Minimal APIs |
| ๐งฉ Generator | Auto-generates union types via [GenerateAny] or Any<T1..Tn> |
| ๐งฉ Model Binding | All types are Controller / Minimal-API Binding Ready |
๐ Get Started
๐ฆ Install Core Library
dotnet add package MultiType.NET.Core
This gives you:
Any<T1..T16>prebuilt types- Core features like
Match,Map,Switch,TryMatch, ...etc - JSON support via converter factory
๐ง Add Optional Source Generators
| Package | Description |
|---|---|
MultiType.NET.Generator |
Adds [GenerateAny(typeof(...))] support |
MultiType.NET.SourceGenerator |
Enables Any<T1..Tn> (over 16 types), JSON support, API integration |
dotnet add package MultiType.NET.Generator
This allow you to generate a custom types with [GenerateAny], for more details MultiType.NET.Generator attribute.
[GenerateAny(typeof(string), typeof(MyType))]
public partial struct MyCustomType{}
This will generate MyCustomType with all MultiType APIs.
Need to generate Any<T17, ..., Tn>?
Install the official CLI generator:
dotnet tool install --global MultiType.NET.SourceGenerator
Then run:
multitypegen --maxArity 50 --project PATH_TO_TARGET_PROJECT.csproj
for more details and documentation MultiType.NET.SourceGenerator CLI
๐ก Learn by Example
Any<int, string, DateTime> result = "hello";
string output = result.Match(
i => $"Int: {i}",
s => $"String: {s}",
d => $"Date: {d:yyyy-MM-dd}"
);
// Using generic Any<T1, T2, T3> directly from body
[HttpPost("process-multi-type")]
public async Task<IActionResult> ProcessMultiTypeData(
[FromBody] Any<int, string, DateTime> requestData)
{
// Example usage: requestData.Match(...)
return Ok();
}
// Using generic Any<T1, T2, T3> from query string (less typical, but possible)
[HttpGet("query-multi-type")]
public async Task<IActionResult> QueryMultiTypeData(
[FromQuery] Any<int, string, DateTime> queryData)
{
return Ok();
}
if (result.TryGetT1(out var i, out var remainder))
Console.WriteLine($"Was int: {i}");
else
Console.WriteLine($"Not an int: {remainder}");
var summary = result.Select(
i => $"# {i}",
s => s.ToUpperInvariant(),
d => d.ToShortTimeString()
);
๐งฑ Creating Any Values
MultiType.NET offers multiple ways to construct union values.
โ
From(...) โ dynamic dispatch
object raw = 123;
var value = Any<int, string, DateTime>.From(raw);
๐ก Throws if the value is not one of the allowed types.
โ
TryFrom(...) โ safe version
if (Any<int, string>.TryFrom(someValue, out var result))
{
// Use result
}
โ
FromTn(...) โ type-specific creation
var a = Any<int, string, bool>.FromT1(42);
var b = Any<int, string, bool>.FromT2("hello");
๐ก These are especially useful for code generation, dynamic input handling, or overload clarity.
โ Implicit Operators
Any<int, string> v1 = 5;
Any<int, string> v2 = "done";
๐ฆ JSON Serialization
MultiType.NET works seamlessly with System.Text.Json without any manual changes.
โ Per-type registration
public readonly partial struct MyUnionType;
๐งช Example
var options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(Any<int, string>.From(123), options);
๐ก JSON output includes both the value and the represented type.
๐งฉ Custom Types with [GenerateAny]
โ ๏ธ Requires
MultiType.NET.Generatorinstalled.
[GenerateAny(typeof(int), typeof(string), typeof(Guid))]
public partial struct Payload;
// POST endpoint accepting Payload from body
[HttpPost("submit-payload")]
public async Task<IActionResult> SubmitPayload(
[FromBody] Payload payload)
{
// payload.Match(...)
return Ok();
}
// GET endpoint accepting Payload from query
[HttpGet("search")]
public async Task<IActionResult> SearchPayload(
[FromQuery] Payload query)
{
return Ok();
}
Payload payload = Guid.NewGuid();
payload.Match(
i => Console.WriteLine($"Int: {i}"),
s => Console.WriteLine($"Str: {s}"),
g => Console.WriteLine($"Guid: {g}")
);
** More advanced Type**
[GenerateAny(typeof(Success), typeof(Warning), typeof(Error), typeof(Info))]
public partial struct StatusType
{
public static StatusType From(string value) => value.ToLowerInvariant() switch
{
"success" => new Success(),
"warning" => new Warning(),
"error" => new Error(),
"info" => new Info(),
_ => throw new ArgumentException("Invalid status", nameof(value))
};
public bool IsSuccess => this.Is<Success>();
public bool IsWarning => this.Is<Warning>();
public bool IsError => this.Is<Error>();
public bool IsInfo => this.Is<Info>();
public readonly struct Success { }
public readonly struct Warning { }
public readonly struct Error { }
public readonly struct Info { }
}
โ๏ธ How It Works (Behind the Scenes)
Any<T1, ..., Tn>is a readonly struct with internal value/ref handling.- Tracks active type via
TypeIndex - Source generators:
- Generate custom union types with all logic
- Auto-wire JSON support
- Add full method surface (Match, Map, Select, etc.)
๐งช Real-World Use Cases
| Use Case | Example |
|---|---|
| โ API Results | Any<SuccessDto, ErrorDto> |
| ๐งโโ๏ธ Workflow Results | Any<Approved, Rejected, Escalated> |
| ๐ง State Modeling | Any<Draft, Submitted, Published> |
| ๐งพ Flexible Inputs | Any<string, int, bool> |
| ๐ Retry Backoff | Any<RetryLater, Fail, Success> |
๐ Project Structure
| Project | Description |
|---|---|
MultiType.NET.Core |
Runtime types and logic |
MultiType.NET.Generator |
[GenerateAny] source generation |
MultiType.NET.SourceGenerator |
JSON + Any<T1..Tn> generation |
๐ Documentation
| Resource | Link |
|---|---|
| ๐ Advanced Features | docs/AdvancedFeatures.md |
| ๐ง Generator Guide | docs/SourceGenerators.md |
| ๐ก Integration Tips | docs/Integration.md |
๐ Contributing
Contributions, issues, and PRs are welcome!
See CONTRIBUTING.md to get started.
๐ License
MIT โ LICENSE
Because type safety shouldn't be optional.
| 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
- 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 |
|---|---|---|
| 1.0.1 | 173 | 7/2/2025 |