DiscriminatedUnion.CS
0.0.8-alpha
dotnet add package DiscriminatedUnion.CS --version 0.0.8-alpha
NuGet\Install-Package DiscriminatedUnion.CS -Version 0.0.8-alpha
<PackageReference Include="DiscriminatedUnion.CS" Version="0.0.8-alpha" />
paket add DiscriminatedUnion.CS --version 0.0.8-alpha
#r "nuget: DiscriminatedUnion.CS, 0.0.8-alpha"
// Install DiscriminatedUnion.CS as a Cake Addin #addin nuget:?package=DiscriminatedUnion.CS&version=0.0.8-alpha&prerelease // Install DiscriminatedUnion.CS as a Cake Tool #tool nuget:?package=DiscriminatedUnion.CS&version=0.0.8-alpha&prerelease
Discriminated Union
A library that provides functionality to define a Discriminated Union in C#.
Define some types
public class Success<T>
{
public Success(T value)
{
Value = value;
}
public T Value { get; }
public void A<V>() { }
public static void B<V>() { }
}
public class Error
{
public Error(string message)
{
Message = message;
}
public string Message { get; init; }
}
Define union type
Union type must be an abstract, partial class marked with [GeneratedDiscriminatedUnion]
attribute.
Every implementation of IDiscriminator<T>
defines a discriminator inside the union type.
Where T
is the type that constraints a discriminator.
[GeneratedDiscriminatedUnion]
public abstract partial class Result<T> : IDiscriminator<Success<T>>, IDiscriminator<Error> { }
Use the union type
public class Program
{
public static void Main(string[] args)
{
var result = GetRoot(-1);
var outputMessage = result switch
{
Result<double>.Success s => s.Value.ToString(CultureInfo.InvariantCulture),
Result<double>.Error e => e.Message,
};
Console.WriteLine(outputMessage);
}
public static Result<double> GetRoot(double value)
{
return value switch
{
< 0 => new Error("Value cannot be less than zero"),
_ => new Success<double>(Math.Sqrt(value)),
};
}
}
Custom named discriminators
To set custom names to discriminator a naming types
are used.
Put a type you want to infer name from as a second generic argument.
[GeneratedDiscriminatedUnion]
public abstract partial class B : IDiscriminator<int>, IDiscriminator<int, OtherInt32> { }
If a type does not exist, it must not have any qualification (ex: wrong - A.B
, right - B
). If non exising type is specified correctly, a dummy class would be generated.
internal sealed class OtherInt32
{
private OtherInt32()
{
}
}
Generic parameter as wrapped type
Discriminator with generic wrapped type must have a naming type
specified.
[GeneratedDiscriminatedUnion]
public abstract partial class GenericResult<T> : IDiscriminator<T, Success>, IDiscriminator<Error> { }
In case of a generic wrapped type, members cannot be inferred during source generation because corresponding closed types are not available as a source code, so discriminator would have a get-only property, containing wrapped value (constraint interfaces implementation t.b.a.).
The wrapped value containing property name is inferred from generic parameter name according this schema:
T
→Value
T*
→*
*
→*
Limitations
- Discriminators of same type does not have a
WrappedType -> UnionType
converter. - Discriminators do not implement interfaces that wrapped types are implementing.
- Discriminators with generic wrapped types do not implement interfaces that generic parameters are constraint with.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- DiscriminatedUnion.CS.Annotations (>= 0.0.4-alpha)
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.0.8-alpha | 147 | 4/22/2022 |
0.0.7-alpha | 132 | 4/21/2022 |
0.0.6-alpha | 136 | 4/19/2022 |
0.0.5-alpha | 155 | 4/19/2022 |
0.0.4-alpha | 126 | 4/18/2022 |
0.0.3-alpha | 120 | 4/17/2022 |
0.0.2-alpha | 143 | 3/2/2022 |
0.0.1-alpha | 131 | 2/28/2022 |
Basic generic wrapped types support.