AltaSoft.Choice
1.3.1
dotnet add package AltaSoft.Choice --version 1.3.1
NuGet\Install-Package AltaSoft.Choice -Version 1.3.1
<PackageReference Include="AltaSoft.Choice" Version="1.3.1" />
<PackageVersion Include="AltaSoft.Choice" Version="1.3.1" />
<PackageReference Include="AltaSoft.Choice" />
paket add AltaSoft.Choice --version 1.3.1
#r "nuget: AltaSoft.Choice, 1.3.1"
#addin nuget:?package=AltaSoft.Choice&version=1.3.1
#tool nuget:?package=AltaSoft.Choice&version=1.3.1
AltaSoft.Choice
AltaSoft.ChoiceGenerator is a lightweight C# source generator that allows you to define choice types (discriminated unions) with minimal syntax.
✨ Features
- Simple
[Choice]
attribute for defining alternatives - Generates type-safe properties
- Supports XML and System.Text.Json serialization
- Includes
CreateAsXxx
,Match
, andSwitch
methods - Auto-generates enum for valid choice types
- Implicit conversion operators for easy usage
- Generates XmlSerializer
🛠️ Installation
Add the following NuGet packages to your project:
<ItemGroup>
<PackageReference Include="AltaSoft.Choice" Version="x.x.x" />
<PackageReference Include="AltaSoft.Choice.Generator" Version="x.x.x" PrivateAssets="all" />
</ItemGroup>
✅ Define Your Choice Type
Mark your class with [Choice]
and define partial nullable properties :
using AltaSoft.Choice;
namespace AltaSoft.ChoiceGenerator.Tests;
[Choice]
public sealed partial class Authorisation1Choice
{
/// <summary>
/// <para>Specifies the authorisation, in a coded form.</para>
/// </summary>
[XmlTag("Cd")]
[JsonPropertyName("cd")]
public partial Authorisation1Code? Code { get; set; }
/// <summary>
/// <para>Specifies the authorisation, in a free text form.</para>
/// </summary>
[XmlTag("Prtry")]
public partial Proprietary? Proprietary { get; set; }
}
⚙️ Generated Code
Below is the generated code for the example above:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by 'AltaSoft Choice.Generator'.
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
#nullable enable
using AltaSoft.ChoiceGenerator.Tests;
using AltaSoft.Choice;
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;
namespace AltaSoft.ChoiceGenerator.Tests;
#pragma warning disable CS8774 // Member must have a non-null value when exiting.
#pragma warning disable CS0628 // New protected member declared in sealed type
public sealed partial record Authorisation1Choice
{
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public Authorisation1Choice()
{
}
/// <summary>
/// <para>Choice enum </para>
/// </summary>
[JsonIgnore]
[XmlIgnore]
public ChoiceOf ChoiceType { get; private set; }
private AltaSoft.ChoiceGenerator.Tests.Authorisation1Code? _code;
/// <summary>
/// Specifies the authorisation, in a coded form.
/// </summary>
[DisallowNull]
[XmlElement("Cd")]
public partial AltaSoft.ChoiceGenerator.Tests.Authorisation1Code? Code
{
get => _code;
set
{
_code = value ?? throw new InvalidOperationException("Choice value cannot be null");
_proprietary = null;
ChoiceType = ChoiceOf.Code;
}
}
private Proprietary? _proprietary;
/// <summary>
/// Specifies the authorisation, in a free text form.
/// </summary>
[DisallowNull]
[XmlElement("Prtry")]
public partial Proprietary? Proprietary
{
get => _proprietary;
set
{
_proprietary = value ?? throw new InvalidOperationException("Choice value cannot be null");
_code = null;
ChoiceType = ChoiceOf.Proprietary;
}
}
/// <summary>
/// Creates a new <see cref="AltaSoft.ChoiceGenerator.Tests.Authorisation1Choice"/> instance and sets its value using the specified <see cref="AltaSoft.ChoiceGenerator.Tests.Authorisation1Code"/>.
/// </summary>
/// <param name="value">The value to assign to the created choice instance.</param>
public static AltaSoft.ChoiceGenerator.Tests.Authorisation1Choice CreateAsCode(AltaSoft.ChoiceGenerator.Tests.Authorisation1Code value) => new () { Code = value };
/// <summary>
/// Creates a new <see cref="AltaSoft.ChoiceGenerator.Tests.Authorisation1Choice"/> instance and sets its value using the specified <see cref="Proprietary"/>.
/// </summary>
/// <param name="value">The value to assign to the created choice instance.</param>
public static AltaSoft.ChoiceGenerator.Tests.Authorisation1Choice CreateAsProprietary(Proprietary value) => new () { Proprietary = value };
/// <summary>
/// <para>Applies the appropriate function based on the current choice type</para>
/// </summary>
/// <typeparam name="TResult">The return type of the provided match functions</typeparam>
/// <param name="matchCode">Function to invoke if the choice is a <see cref="ChoiceOf.Code"/> value</param>
/// <param name="matchProprietary">Function to invoke if the choice is a <see cref="ChoiceOf.Proprietary"/> value</param>
public TResult Match<TResult>(
Func<AltaSoft.ChoiceGenerator.Tests.Authorisation1Code, TResult> matchCode,
Func<Proprietary, TResult> matchProprietary)
{
return ChoiceType switch
{
ChoiceOf.Code => matchCode(Code!.Value),
ChoiceOf.Proprietary => matchProprietary(Proprietary!),
_ => throw new InvalidOperationException($"Invalid ChoiceType. '{ChoiceType}'")
};
}
/// <summary>
/// <para>Applies the appropriate Action based on the current choice type</para>
/// </summary>
/// <param name="matchCode">Action to invoke if the choice is a <see cref="ChoiceOf.Code"/> value</param>
/// <param name="matchProprietary">Action to invoke if the choice is a <see cref="ChoiceOf.Proprietary"/> value</param>
public void Switch(
Action<AltaSoft.ChoiceGenerator.Tests.Authorisation1Code> matchCode,
Action<Proprietary> matchProprietary)
{
switch (ChoiceType)
{
case ChoiceOf.Code:
matchCode(Code!.Value);
return;
case ChoiceOf.Proprietary:
matchProprietary(Proprietary!);
return;
default:
throw new XmlException($"Invalid ChoiceType. '{ChoiceType}'");
}
}
/// <summary>
/// Implicitly converts an <see cref="AltaSoft.ChoiceGenerator.Tests.Authorisation1Code"/> to an <see cref="Authorisation1Choice"/>.
/// </summary>
/// <param name="value">The <see cref="AltaSoft.ChoiceGenerator.Tests.Authorisation1Code"/> to convert.</param>
/// <returns>
/// <see cref="Authorisation1Choice"/> instance representing the code.
/// </returns>
public static implicit operator Authorisation1Choice(AltaSoft.ChoiceGenerator.Tests.Authorisation1Code value) => CreateAsCode(value);
/// <summary>
/// Implicitly converts an <see cref="Proprietary"/> to an <see cref="Authorisation1Choice"/>.
/// </summary>
/// <param name="value">The <see cref="Proprietary"/> to convert.</param>
/// <returns>
/// <see cref="Authorisation1Choice"/> instance representing the code.
/// </returns>
public static implicit operator Authorisation1Choice(Proprietary value) => CreateAsProprietary(value);
/// <summary>
/// Determines whether the <see cref="Code"/> property should be serialized.
/// </summary>
/// <returns>
/// <c>true</c> if <see cref="Code"/> has a value; otherwise, <c>false</c>.
/// </returns>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeCode() => Code.HasValue;
/// <summary>
/// <para>Choice enumeration</para>
/// </summary>
[XmlType("ChoiceOf.Authorisation1Choice")]
public enum ChoiceOf
{
/// <summary>
/// Specifies the authorisation, in a coded form.
/// </summary>
Code,
/// <summary>
/// Specifies the authorisation, in a free text form.
/// </summary>
Proprietary,
}
}
💡 Example Usage
Creating with CreateAs methods
var choice = Authorisation1Choice.CreateAsCode(Authorisation1Code.FileLevelAuthorisationSummary);
var result = choice.Match(
code => $"It's a code: {code}",
prop => $"It's proprietary: {prop.ToString()}"
);
choice.Switch(
code => Console.WriteLine($"String: {code}"),
prop => Console.WriteLine($"Number: {prop.ToString()}")
);
Creating using implicit operators
if property types are distinct implicit operators are generated
Authosiration1Choice choice = Authorisation1Code.FileLevelAuthorisationSummary;
📦 Projects
AltaSoft.Choice
Contains the[Choice]
marker attributeAltaSoft.Choice.Generator
Implements the source generator that produces boilerplate code
📄 License
This project is licensed under the MIT License.
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 is compatible. 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.
-
net9.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.