RSCG – UnionsGenerator
Generating Union types for C#
This is how you can use UnionsGenerator .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RhoMicro.CodeAnalysis.UnionsGenerator" Version="14.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
The code that you will use is
using UnionTypesDemo;
Console.WriteLine("Save or not");
var data = SaveToDatabase.Save(0);
Console.WriteLine(data.IsValidationError);
data = SaveToDatabase.Save(1);
Console.WriteLine(data.IsSuccess);
using RhoMicro.CodeAnalysis;
namespace UnionTypesDemo;
public record Success(int Value);
public record ValidationError(string Message);
[UnionType<Success>]
[UnionTypeAttribute<ValidationError>]
public partial class ResultSave
{
}
namespace UnionTypesDemo;
public class SaveToDatabase
{
public static ResultSave Save(int i)
{
if(i ==0)
{
return new ValidationError(" cannot save 0");
}
return new Success(i);
}
}
The code that is generated is
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable
namespace RhoMicro.CodeAnalysis
{
using System;
/// <summary>
/// Marks the target type to be related to another union type.
/// </summary>
/// <typeparam name="T0">The type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
#if UNIONS_GENERATOR
[GenerateFactory(OmitTypeCheck = true)]
#endif
sealed partial class RelationAttribute<T0> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
/// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1, T2> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
/// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
/// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1, T2, T3> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
/// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
/// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
/// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1, T2, T3, T4> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
/// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
/// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
/// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
/// <typeparam name="T5">The sixth type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1, T2, T3, T4, T5> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
/// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
/// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
/// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
/// <typeparam name="T5">The sixth type to register as related to the target union type.</typeparam>
/// <typeparam name="T6">The seventh type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1, T2, T3, T4, T5, T6> : Attribute
{ }
/// <summary>
/// Marks the target type to be related to other union types.
/// </summary>
/// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
/// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
/// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
/// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
/// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
/// <typeparam name="T5">The sixth type to register as related to the target union type.</typeparam>
/// <typeparam name="T6">The seventh type to register as related to the target union type.</typeparam>
/// <typeparam name="T7">The eighth type to register as related to the target union type.</typeparam>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class RelationAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : Attribute
{ }
}
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable
namespace RhoMicro.CodeAnalysis
{
using System;
/// <summary>
/// Marks the target method as the factory method to use when instantiating
/// an instance of the union type representing a value of the annotated parameter.
/// Factory methods must be static, have no type parameters and only have one
/// parameter of a type representable by the union type.
/// Factory polymorphism is not yet supported.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
#if UNIONS_GENERATOR
[GenerateFactory]
#endif
sealed partial class UnionTypeFactoryAttribute : Attribute
{ }
}
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable
namespace RhoMicro.CodeAnalysis.UnionsGenerator.Generated
{
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
internal static class Util
{
private readonly static ConcurrentDictionary<Type, String> _cache = new();
internal static String GetFullString(Type type) => _cache.GetOrAdd(type, ValueFactory);
static String ValueFactory(Type type)
{
var result = getString(type, new());
return result;
static String getString(Type type, StringBuilder builder)
{
var unboundTransitiveParameters = 0;
var transitiveParameters = new List<(String Format, Type? Argument)>();
append(type, builder, transitiveParameters, ref unboundTransitiveParameters);
var result = builder.ToString();
for(var i = 0; i < transitiveParameters.Count; i++)
{
_ = builder.Clear();
var (format, argument) = transitiveParameters[i];
var replacement = getString(argument!, builder);
result = result.Replace(format, replacement);
}
return result;
static void append(
Type type,
StringBuilder builder,
List<(String Format, Type? Argument)> transitiveArgumentsMap,
ref Int32 unboundTransitiveParameters)
{
#if NETSTANDARD2_0
if(type.IsGenericParameter && type.DeclaringMethod is null)
#else
if(type.IsGenericTypeParameter)
#endif
{
var format = $"{Guid.NewGuid()}";
_ = builder.Append(format);
transitiveArgumentsMap.Add((format, null));
unboundTransitiveParameters++;
return;
} else if(type.DeclaringType != null)
{
append(type.DeclaringType, builder, transitiveArgumentsMap, ref unboundTransitiveParameters);
_ = builder.Append('.');
} else if(type.Namespace != null)
{
_ = builder.Append(type.Namespace)
.Append('.');
}
var tickIndex = type.Name.IndexOf('`');
_ = tickIndex != -1 ?
#if NETSTANDARD2_0
builder.Append(type.Name.Substring(0, tickIndex)) :
#else
builder.Append(type.Name.AsSpan(0, tickIndex)) :
#endif
builder.Append(type.Name);
var arguments = type.GetGenericArguments();
var inflectionPoint = unboundTransitiveParameters;
if(arguments.Length > 0 && unboundTransitiveParameters > 0)
{
for(; unboundTransitiveParameters > 0;)
{
unboundTransitiveParameters--;
var (format, _) = transitiveArgumentsMap[unboundTransitiveParameters];
transitiveArgumentsMap[unboundTransitiveParameters] = (format, arguments[unboundTransitiveParameters]);
}
}
if(arguments.Length > inflectionPoint)
{
_ = builder.Append('<');
append(arguments[inflectionPoint], builder, transitiveArgumentsMap, ref unboundTransitiveParameters);
for(var i = inflectionPoint + 1; i < type.GenericTypeArguments.Length; i++)
{
_ = builder.Append(", ");
append(arguments[i], builder, transitiveArgumentsMap, ref unboundTransitiveParameters);
}
_ = builder.Append('>');
}
}
}
}
internal static System.Boolean IsMarked(Type type) =>
type.CustomAttributes.Any(a => a.AttributeType.FullName == "RhoMicro.CodeAnalysis.UnionTypeAttribute") ||
type.GenericTypeArguments.Any(t => t.CustomAttributes.Any(a =>
a.AttributeType.FullName.StartsWith("RhoMicro.CodeAnalysis.UnionTypeAttribute`")
&& a.AttributeType.GenericTypeArguments.Length < 255));
private static readonly System.Collections.Concurrent.ConcurrentDictionary<(Type, Type), Object> _conversionImplementations = new();
internal static TTo UnsafeConvert<TFrom, TTo>(in TFrom from)
{
var impl = (System.Func<TFrom, TTo>)_conversionImplementations.GetOrAdd((typeof(TFrom), typeof(TTo)), k =>
{
var param = System.Linq.Expressions.Expression.Parameter(k.Item1);
var castExpr = System.Linq.Expressions.Expression.Convert(param, k.Item2);
var lambda = System.Linq.Expressions.Expression.Lambda(castExpr, param).Compile();
return lambda;
});
var result = impl.Invoke(from);
return result;
}
}
}
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable
namespace RhoMicro.CodeAnalysis
{
using System;
using System.Collections.Generic;
/// <summary>
/// Defines options for generating union types.
/// </summary>
[Flags]
enum UnionTypeOptions
{
/// <summary>
/// The default options.
/// </summary>
Default = ImplicitConversionIfSolitary,
/// <summary>
/// </summary>
None = 0x00,
/// <summary>
/// Instructs the generator to emit an implicit conversion to the representable type if it is the only one.
/// In effect, this option will enable the union type to act as an alias wrapper for the representable type.
/// </summary>
ImplicitConversionIfSolitary = 0x01,
/// <summary>
/// Instructs the generator to emit a superset conversion operator implementation even though
/// the representable type is a generic type parameter. By default, it is omitted because of possible
/// unification for certain generic arguments.
/// </summary>
//SupersetOfParameter = 0x02,
/// <summary>
/// Instructs the generator to treat the representable reference type
/// as nullable, allowing for <see langword="null"/>
/// arguments in factories, conversions etc.
/// </summary>
Nullable = 0x04
}
/// <summary>
/// Defines options for the storage implementation of a representable type.
/// In order for the generator to generate an efficient storage implementation,
/// consumers should communicate whether the representable type is known to
/// be a struct, class or of unknown nature. This is mostly relevant for generic
/// type parameters, however an explicit strategy may be selected for any representable
/// type. Whether or not generic type parameters are known to be reference
/// or value types depends on their constraints. Parameters constrained to
/// <see langword="struct"/> will be assumed to be value types. Conversely,
/// parameters constrained to <see langword="class"/> will be assumed to be reference types.
/// </summary>
/*
| box |value| auto | field
struct | rc! | vc | vc | cc
class | rc | rc! | rc | cc
none | rc! | vc! | rc! | cc
*/
enum StorageOption
{
/// <summary>
/// The generator will automatically decide on a storage strategy.
/// <para>
/// If the representable type is <b>known to be a value type</b>,
/// this will store values of that type inside a shared value type container.
/// <b>Boxing will not occur.</b>
/// </para>
/// <para>
/// If the representable type is <b>known to be a reference type</b>,
/// this will store values of that type inside a shared reference type container.
/// </para>
/// <para>
/// If the representable type is <b>neither known to be a reference type
/// nor a value type</b>, this option will cause values of that type to
/// be stored inside a shared reference type container.
/// <b>If the representable type is a generic type parameter,
/// boxing will occur for value type arguments to that parameter.</b>
/// </para>
/// </summary>
Auto,
/// <summary>
/// The generator will always store values of the representable type
/// inside a shared reference type container.
/// <para>
/// If the representable type is <b>known to be a value type</b>,
/// <b>boxing will occur</b>.
/// </para>
/// <para>
/// If the representable type is a <b>generic type parameter</b>,
/// <b>boxing will occur for value type arguments</b> to that parameter.
/// </para>
/// </summary>
Reference,
/// <summary>
/// The generator will attempt to store values of the representable type
/// inside a value type container.
/// <para>
/// If the representable type is <b>known to be a value type</b>,
/// this will store values of that type inside a shared value type container.
/// <b>Boxing will not occur.</b>
/// </para>
/// <para>
/// If the representable type is <b>known to be a reference type</b>,
/// this will store values of that type inside a shared reference type container.
/// <b>Boxing will not occur.</b>
/// </para>
/// <para>
/// If the representable type is <b>neither known to be a reference type
/// nor a value type</b>, this option will cause values of that type to
/// be stored inside a shared value type container.
/// <b>If the representable type is a generic type parameter,
/// an exception of type <see cref="TypeLoadException"/> will occur for
/// reference type arguments to that parameter.</b>
/// </para>
/// </summary>
Value,
/// <summary>
/// The generator will attempt to store values of the representable type
/// inside a dedicated container for that type.
/// <para>
/// If the representable type is <b>known to be a value type</b>,
/// this will store values of that type inside a dedicated
/// value type container.
/// <b>Boxing will not occur.</b>
/// </para>
/// <para>
/// If the representable type is <b>known to be a reference type</b>,
/// this will store values of that type inside a
/// dedicated reference type container.
/// </para>
/// <para>
/// If the representable type is <b>neither known to be a reference type
/// nor a value type</b>, this option will cause values of that type to
/// be stored inside a dedicated strongly typed container.
/// <b>Boxing will not occur.</b>
/// </para>
/// </summary>
Field
}
/// <summary>
/// Marks the target type as a union type being able to represent the type passed to the constructor.
/// </summary>
[AttributeUsage(( (AttributeTargets)( -1 ) ))]
partial class UnionTypeBaseAttribute : Attribute
{
/// <summary>
/// Gets or sets the alias groups that the representable type is to be a part of.
/// Represnetable types that share a group may be checked for using unified methods
/// and properties like <c>IsGroup</c> where <c>Group</c> is the name of the group
/// that the representable type is a part of.
/// </summary>
public virtual String[] Groups { get; set; } = Array.Empty<String>();
/// <summary>
/// Gets or sets the generator options to use.
/// </summary>
public virtual UnionTypeOptions Options { get; set; } = UnionTypeOptions.Default;
/// <summary>
/// Gets or sets the option defining storage generation.
/// </summary>
public virtual StorageOption Storage { get; set; }
}
[AttributeUsage(( (AttributeTargets)( -1 ) ))]
#if UNIONS_GENERATOR
[GenerateFactory(OmitTypeCheck = true)]
#endif
partial class AliasedUnionTypeBaseAttribute : UnionTypeBaseAttribute
{
/// <summary>
/// Gets or sets the alias to use for members representing the type represented by the union.
/// For example, the represented type <see cref="List{T}"/> would be represented using names like
/// <c>list_of_T</c>. Setting this property to <c>yourAlias</c> will instruct the generator to use
/// member names like <c>yourAlias</c> instead of <c>list_of_T</c>. Use this property to avoid
/// name collisions in generated code. Since the alias will be used for member names, it will
/// only be taken into account if it is a valid identifier name.
/// </summary>
public String? Alias { get; set; }
/// <inheritdoc/>
public override String[] Groups { get => base.Groups; set => base.Groups = value; }
/// <inheritdoc/>
public override UnionTypeOptions Options { get => base.Options; set => base.Options = value; }
/// <inheritdoc/>
public override StorageOption Storage { get => base.Storage; set => base.Storage = value; }
}
/// <summary>
/// Marks the target type as a union type being able to represent <typeparamref name="T0"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0> : AliasedUnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>
/// and <typeparamref name="T1"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>,
/// <typeparamref name="T1"/>
/// and <typeparamref name="T2"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1, T2> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>,
/// <typeparamref name="T1"/>,
/// <typeparamref name="T2"/>
/// and <typeparamref name="T3"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1, T2, T3> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>,
/// <typeparamref name="T1"/>,
/// <typeparamref name="T2"/>,
/// <typeparamref name="T3"/>
/// and <typeparamref name="T4"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>,
/// <typeparamref name="T1"/>,
/// <typeparamref name="T2"/>,
/// <typeparamref name="T3"/>,
/// <typeparamref name="T4"/>
/// and <typeparamref name="T5"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4, T5> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>,
/// <typeparamref name="T1"/>,
/// <typeparamref name="T2"/>,
/// <typeparamref name="T3"/>,
/// <typeparamref name="T4"/>,
/// <typeparamref name="T5"/>
/// and <typeparamref name="T6"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4, T5, T6> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent
/// <typeparamref name="T0"/>,
/// <typeparamref name="T1"/>,
/// <typeparamref name="T2"/>,
/// <typeparamref name="T3"/>,
/// <typeparamref name="T4"/>,
/// <typeparamref name="T5"/>,
/// <typeparamref name="T6"/>
/// and <typeparamref name="T7"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : UnionTypeBaseAttribute
{ }
/// <summary>
/// Marks the target type as a union type being able to represent the annotated type parameter.
/// </summary>
[AttributeUsage(AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
sealed partial class UnionTypeAttribute : AliasedUnionTypeBaseAttribute
{ }
}
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable
namespace RhoMicro.CodeAnalysis;
using System;
#region Setting Enums
/// <summary>
/// Defines settings for generating an implementation of <see cref="Object.ToString"/>.
/// </summary>
enum ToStringSetting
{
/// <summary>
/// The generator will emit an implementation that returns detailed information, including:
/// <list type="bullet">
/// <item><description>the name of the union type</description></item>
/// <item><description>a list of types representable by the union type</description></item>
/// <item><description>an indication of which type is being represented by the instance</description></item>
/// <item><description>the value currently being represented by the instance</description></item>
/// </list>
/// </summary>
Detailed,
/// <summary>
/// The generator will not generate an implementation of <see cref="Object.ToString"/>.
/// </summary>
None,
/// <summary>
/// The generator will generate an implementation that returns the result of calling <see cref="Object.ToString"/> on the currently represented value.
/// </summary>
Simple
}
/// <summary>
/// Defines settings for annotating the target with an instance of <see cref="System.Runtime.InteropServices.StructLayoutAttribute"/>.
/// </summary>
enum LayoutSetting
{
/// <summary>
/// Generate an annotation optimized for size.
/// </summary>
Small,
/// <summary>
/// Do not generate any annotations.
/// </summary>
Auto
}
/// <summary>
/// Defines settings for controlling the accessibility of generated constructors.
/// </summary>
enum ConstructorAccessibilitySetting
{
/// <summary>
/// Generated constructors should always be private, unless
/// no conversion operators are generated for the type they
/// accept. This would be the case for interface types or
/// supertypes of the target union.
/// </summary>
PublicIfInconvertible,
/// <summary>
/// Generated constructors should always be private.
/// </summary>
Private,
/// <summary>
/// Generated constructors should always be public
/// </summary>
Public
}
/// <summary>
/// Defines settings on how to implement interfaces that all representable
/// types implement.
/// </summary>
enum InterfaceMatchSetting
{
/// <summary>
/// Generated interface implementations should be explicit if at least
/// one of the representable types implements the interface explicitly;
/// otherwise, interface implementations should be implicit.
/// </summary>
Auto,
/// <summary>
/// Generated interface implementations should always be explicit.
/// </summary>
Explicit,
/// <summary>
/// Generated interface implementations should always be implicit.
/// </summary>
Implicit,
/// <summary>
/// No interfaces implementations should be generated.
/// </summary>
Omit
}
/// <summary>
/// Defines settings for the kind of diagnostics to report.
/// </summary>
[Flags]
enum DiagnosticsLevelSettings
{
/// <summary>
/// Instructs the analyzer not to emit diagnostics
/// </summary>
None = 0x00,
/// <summary>
/// Instructs the analyzer to report info diagnostics.
/// </summary>
Info = 0x01,
/// <summary>
/// Instructs the analyzer to report warning diagnostics.
/// </summary>
Warning = 0x02,
/// <summary>
/// Instructs the analyzer to report error diagnostics.
/// </summary>
Error = 0x04,
/// <summary>
/// Instructs the analyzer to report all diagnostics.
/// </summary>
All = Info | Warning | Error
}
/// <summary>
/// Defines miscellaneous settings.
/// </summary>
[Flags]
enum MiscellaneousSettings
{
/// <summary>
/// </summary>
None = 0x00,
/// <summary>
/// The default settings.
/// </summary>
Default = None,
/// <summary>
/// Indicates whether the generated source code should be available as a string constant on the union type itself.
/// This setting is generally only useful if the generated implementation should be emitted from another generator.
/// </summary>
EmitGeneratedSourceCode = 0x01,
/// <summary>
/// Indicates whether to generate a custom converter type
/// for <c>System.Text.Json</c> deserialization. If set, this will also cause
/// the union type to be annotated with an appropriate <c>JsonConverter</c> attribute.
/// </summary>
GenerateJsonConverter = 0x02,
/// <summary>
/// Indicates that the generator should emit a comment detailing the structure of the union type.
/// </summary>
EmitStructuralRepresentation = 0x04
}
/// <summary>
/// Defines settings pertaining to equality operator implementations.
/// </summary>
enum EqualityOperatorsSetting
{
/// <summary>
/// Equality operators will be emitted only if the target union type is a value type.
/// </summary>
EmitOperatorsIfValueType,
/// <summary>
/// Equality operators will be emitted.
/// </summary>
EmitOperators,
/// <summary>
/// Equality operators will be omitted.
/// </summary>
OmitOperators
}
#endregion
#region Attribute Declaration
/// <summary>
/// Supplies the generator with additional settings on how to generate a targeted union type.
/// If the target member is an assembly, the attribute supplies default values for any union
/// type setting not defined.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
#if UNIONS_GENERATOR
[GenerateFactory]
#endif
sealed partial class UnionTypeSettingsAttribute : Attribute
{
#region Settings
/// <summary>
/// Defines how to generate an implementation <see cref="Object.ToString"/>.
/// </summary>
public ToStringSetting ToStringSetting { get; set; } = ToStringSetting.Detailed;
/// <summary>
/// Defines whether to generate a size optimizing annotation.
/// </summary>
public LayoutSetting Layout { get; set; } = LayoutSetting.Auto;
/// <summary>
/// The level of diagnostics to be reported by the analyzer.
/// </summary>
public DiagnosticsLevelSettings DiagnosticsLevel { get; set; } = DiagnosticsLevelSettings.All;
/// <summary>
/// The desired accessibility of generated constructors.
/// </summary>
public ConstructorAccessibilitySetting ConstructorAccessibility { get; set; } = ConstructorAccessibilitySetting.Private;
/// <summary>
/// Indicates how to generate implementations for
/// interfaces implemented by all representable types. Implementations will
/// map calls to interface instance methods and properties onto the represented
/// value.
/// <para>
/// Please note that currently, only fully bound and constructed interface implementations are supported.
/// </para>
/// </summary>
public InterfaceMatchSetting InterfaceMatchSetting { get; set; } = InterfaceMatchSetting.Auto;
/// <summary>
/// Indicates how to generate equality operators.
/// By default, equality operators will only be emitted for value types, so as to preserve
/// reference equality for comparing reference union types via <c>==</c> or <c>!=</c>.
/// </summary>
public EqualityOperatorsSetting EqualityOperatorsSetting { get; set; } = EqualityOperatorsSetting.EmitOperatorsIfValueType;
/// <summary>
/// Gets or sets miscellaneous settings.
/// </summary>
public MiscellaneousSettings Miscellaneous { get; set; } = MiscellaneousSettings.Default;
#endregion
#region Strings
/// <summary>
/// A raw code preface to prepend before the generated type declaration.
/// </summary>
public String TypeDeclarationPreface { get; set; } = "";
/// <summary>
/// The name of the generic parameter for generic <c>Is</c>, <c>As</c> and factory methods.
/// Set this property in order to avoid name collisions with generic union type parameters
/// </summary>
public String GenericTValueName { get; set; } = "TValue";
/// <summary>
/// The name of the generic parameter for the <c>TryConvert</c> method.
/// Set this property in order to avoid name collisions with generic union type parameters
/// </summary>
public String TryConvertTypeName { get; set; } = "TUnion";
/// <summary>
/// The name of the generic parameter for the <c>Match</c> method.
/// Set this property in order to avoid name collisions with generic union type parameters
/// </summary>
public String MatchTypeName { get; set; } = "TMatchResult";
/// <summary>
/// The name to use for the discriminating tag type.
/// </summary>
public String TagTypeName { get; set; } = "__Tag";
/// <summary>
/// The name to use for the container type containing value types.
/// </summary>
public String ValueTypeContainerTypeName { get; set; } = "__ValueTypeContainer";
/// <summary>
/// The name to use for the field containing value types.
/// </summary>
public String ValueTypeContainerName { get; set; } = "__value";
/// <summary>
/// The name to use for the field containing reference types.
/// </summary>
public String ReferenceTypeContainerName { get; set; } = "__reference";
/// <summary>
/// The name to use for the field containing the discriminating tag.
/// </summary>
public String TagFieldName { get; set; } = "__tag";
/// <summary>
/// The name to use for the default (uninitialized) tag value.
/// </summary>
public String TagNoneName { get; set; } = "__None";
/// <summary>
/// The name of the generated json converter type.
/// </summary>
public String JsonConverterTypeName { get; set; } = "JsonConverter";
#endregion
}
#endregion
// <auto-generated>
// This file was last generated by RhoMicro.CodeAnalysis.UnionsGenerator at 2/18/2024 10:51:57 AM +02:00
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#pragma warning disable
#nullable enable
#region Implementation of UnionTypesDemo.ResultSave
namespace UnionTypesDemo
{
using System.Linq;
#region Scoped Data
file static class UnionTypesDemo_ResultSave_ScopedData
{
public static System.Collections.Concurrent.ConcurrentDictionary<System.Type, System.Object> Cache { get; } = new();
public static System.Collections.Generic.HashSet<System.Type> RepresentableTypes { get; } =
new ()
{
typeof(UnionTypesDemo.Success),
typeof(UnionTypesDemo.ValidationError)
}
;
}
#endregion
partial class ResultSave : System.IEquatable<ResultSave?>
{
#region Nested Types
#region Value Type Container
#endregion
#region Tag Type
/// <summary>
/// Defines tags to discriminate between representable types.
/// </summary>
/// <remarks>
/// This member is not intended for use by user code inside of or any code outside of <see cref="UnionTypesDemo.ResultSave"/>.
/// </remarks>
[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
private enum __Tag : System.Byte
{
/// <summary>
/// Used when not representing any type due to e.g. incorrect or missing initialization.
/// </summary>
__None,
/// <summary>
/// Used when representing an instance of <see cref="UnionTypesDemo.Success"/>.
/// </summary>
Success,
/// <summary>
/// Used when representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
ValidationError
}
#endregion
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/>representing an instance of <see cref="UnionTypesDemo.Success"/>.
/// </summary>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
private ResultSave(UnionTypesDemo.Success value)
{
__tag = __Tag.Success;
this.__reference = value;
}
/// <summary>
/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/>representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
private ResultSave(UnionTypesDemo.ValidationError value)
{
__tag = __Tag.ValidationError;
this.__reference = value;
}
#endregion
#region Fields
/// <summary>
/// Contains the value of instances of <see cref="UnionTypesDemo.ResultSave"/> representing one of these types:
/// <list type="bullet">
/// <item>
/// <see cref="UnionTypesDemo.Success"/>
/// </item>
/// <item>
/// <see cref="UnionTypesDemo.ValidationError"/>
/// </item>
/// </list>
/// </summary>
/// <remarks>
/// This member is not intended for use by user code inside of or any code outside of <see cref="UnionTypesDemo.ResultSave"/>.
/// </remarks>
[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
private readonly System.Object? __reference;
/// <summary>
/// Used to determine the currently represented type and value.
/// </summary>
/// <remarks>
/// This member is not intended for use by user code inside of or any code outside of <see cref="UnionTypesDemo.ResultSave"/>.
/// </remarks>
[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
private readonly __Tag __tag;
#endregion
#region Factories
/// <summary>
/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/> representing an instance of <see cref="UnionTypesDemo.Success"/>.
/// </summary>
/// <param name="value">
/// The value to be represented by the new instance of <see cref="UnionTypesDemo.ResultSave"/>.
/// </param>
/// <returns>
/// A new instance of <see cref="UnionTypesDemo.ResultSave"/> representing <paramref name="value"/>.
/// </returns>
public static ResultSave CreateFromSuccess([RhoMicro.CodeAnalysis.UnionTypeFactory]UnionTypesDemo.Success value) => new(value);
/// <summary>
/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/> representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
/// <param name="value">
/// The value to be represented by the new instance of <see cref="UnionTypesDemo.ResultSave"/>.
/// </param>
/// <returns>
/// A new instance of <see cref="UnionTypesDemo.ResultSave"/> representing <paramref name="value"/>.
/// </returns>
public static ResultSave CreateFromValidationError([RhoMicro.CodeAnalysis.UnionTypeFactory]UnionTypesDemo.ValidationError value) => new(value);
/// <summary>
/// Attempts to create an instance of <see cref="UnionTypesDemo.ResultSave"/> from an instance of <typeparamref name="TValue"/>.
/// </summary>
/// <param name="value">
/// The value from which to attempt to create an instance of <see cref="UnionTypesDemo.ResultSave"/>.
/// </param>
/// <param name="result">
/// If an instance of <see cref="UnionTypesDemo.ResultSave"/> could successfully be created, this parameter will contain the newly created instance; otherwise, <see langword="default"/>.
/// </param>
/// <returns>
/// <see langword="true"/> if an instance of <see cref="UnionTypesDemo.ResultSave"/> could successfully be created; otherwise, <see langword="false"/>.
/// </returns>
public static System.Boolean TryCreate<TValue>(TValue value, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ResultSave? result)
{
var metadataName = RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.GetFullString(typeof(TValue));
switch(metadataName)
{
case "UnionTypesDemo.Success":
{
result = CreateFromSuccess((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.Success>(value)));
return true;
}
case "UnionTypesDemo.ValidationError":
{
result = CreateFromValidationError((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.ValidationError>(value)));
return true;
}
default:
{
{
var sourceType = typeof(TValue);
if(!UnionTypesDemo_ResultSave_ScopedData.Cache.TryGetValue(sourceType, out var weakMatch))
{
if(!RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.IsMarked(sourceType))
{
result = default;
return false;
}
weakMatch = UnionTypesDemo_ResultSave_ScopedData.Cache.GetOrAdd(sourceType, t =>
{
var tupleType = typeof(System.ValueTuple<System.Boolean, ResultSave>);
var matchMethod = sourceType.GetMethod(nameof(Match), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
?.MakeGenericMethod(tupleType) ??
throw new System.InvalidOperationException("Unable to locate match function on source union type. This indicates a bug in the marker detection algorithm.");
var targetFactoryMap = typeof(UnionTypesDemo.ResultSave).GetMethods()
.Where(c => c.CustomAttributes.Any(a => a.AttributeType.FullName == "RhoMicro.CodeAnalysis.UnionTypeFactoryAttribute"))
.ToDictionary(c => c.GetParameters()[0].ParameterType);
var handlers = matchMethod.GetParameters()
.Select(p => p.ParameterType.GenericTypeArguments[0])
.Select(t => (ParameterExpr: System.Linq.Expressions.Expression.Parameter(t), ParameterExprType: t))
.Select(t =>
{
var delegateType = typeof(System.Func<,>).MakeGenericType(t.ParameterExprType, tupleType);
System.Linq.Expressions.Expression expression = targetFactoryMap.TryGetValue(t.ParameterExprType, out var factory)
? System.Linq.Expressions.Expression.New(tupleType.GetConstructors()[0], System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Call(factory, t.ParameterExpr))
: System.Linq.Expressions.Expression.Default(tupleType);
return System.Linq.Expressions.Expression.Lambda(delegateType, expression, t.ParameterExpr);
}
);var paramExpr = System.Linq.Expressions.Expression.Parameter(sourceType);
var callExpr = System.Linq.Expressions.Expression.Call(paramExpr, matchMethod, handlers);
var lambdaExpr = System.Linq.Expressions.Expression.Lambda(callExpr, paramExpr);
var result = lambdaExpr.Compile();
return result;
}
);
}
var match = (System.Func<TValue, (System.Boolean, UnionTypesDemo.ResultSave)>)weakMatch;
var matchResult = match.Invoke(value);
if(!matchResult.Item1)
{
result = default;
return false;
}
result = matchResult.Item2;
return true;
}
}
}
}
/// <summary>
/// Creates an instance of <see cref="UnionTypesDemo.ResultSave"/> from an instance of <typeparamref name="TValue"/>.
/// </summary>
/// <param name="value">
/// The value from which to create an instance of <see cref="UnionTypesDemo.ResultSave"/>.
/// </param>
/// <returns>
/// A new instance of <see cref="UnionTypesDemo.ResultSave"/> representing <paramref name="value"/>.
/// </returns>
public static ResultSave Create<TValue>(TValue value)
{
var metadataName = RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.GetFullString(typeof(TValue));
switch(metadataName)
{
case "UnionTypesDemo.Success":
{
return CreateFromSuccess((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.Success>(value)));
}
case "UnionTypesDemo.ValidationError":
{
return CreateFromValidationError((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.ValidationError>(value)));
}
default:
{
{
var sourceType = typeof(TValue);
if(!UnionTypesDemo_ResultSave_ScopedData.Cache.TryGetValue(sourceType, out var weakMatch))
{
if(!RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.IsMarked(sourceType))
{
throw new System.InvalidOperationException($"Unable to create an instance of UnionTypesDemo.ResultSave from an instance of {typeof(TValue)}.");
}
weakMatch = UnionTypesDemo_ResultSave_ScopedData.Cache.GetOrAdd(sourceType, t =>
{
var tupleType = typeof(System.ValueTuple<System.Boolean, ResultSave>);
var matchMethod = sourceType.GetMethod(nameof(Match), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
?.MakeGenericMethod(tupleType) ??
throw new System.InvalidOperationException("Unable to locate match function on source union type. This indicates a bug in the marker detection algorithm.");
var targetFactoryMap = typeof(UnionTypesDemo.ResultSave).GetMethods()
.Where(c => c.CustomAttributes.Any(a => a.AttributeType.FullName == "RhoMicro.CodeAnalysis.UnionTypeFactoryAttribute"))
.ToDictionary(c => c.GetParameters()[0].ParameterType);
var handlers = matchMethod.GetParameters()
.Select(p => p.ParameterType.GenericTypeArguments[0])
.Select(t => (ParameterExpr: System.Linq.Expressions.Expression.Parameter(t), ParameterExprType: t))
.Select(t =>
{
var delegateType = typeof(System.Func<,>).MakeGenericType(t.ParameterExprType, tupleType);
System.Linq.Expressions.Expression expression = targetFactoryMap.TryGetValue(t.ParameterExprType, out var factory)
? System.Linq.Expressions.Expression.New(tupleType.GetConstructors()[0], System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Call(factory, t.ParameterExpr))
: System.Linq.Expressions.Expression.Default(tupleType);
return System.Linq.Expressions.Expression.Lambda(delegateType, expression, t.ParameterExpr);
}
);var paramExpr = System.Linq.Expressions.Expression.Parameter(sourceType);
var callExpr = System.Linq.Expressions.Expression.Call(paramExpr, matchMethod, handlers);
var lambdaExpr = System.Linq.Expressions.Expression.Lambda(callExpr, paramExpr);
var result = lambdaExpr.Compile();
return result;
}
);
}
var match = (System.Func<TValue, (System.Boolean, UnionTypesDemo.ResultSave)>)weakMatch;
var matchResult = match.Invoke(value);
if(!matchResult.Item1)
{
throw new System.InvalidOperationException($"Unable to create an instance of UnionTypesDemo.ResultSave from an instance of {typeof(TValue)}.");
}
return matchResult.Item2;
}
}
}
}
#endregion
#region Switch
/// <summary>
/// Invokes a handler based on the type of value being represented.
/// </summary>
/// <param name="onSuccess">
/// The handler to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.Success"/>.
/// </param>
/// <param name="onValidationError">
/// The handler to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
/// </param>
public void Switch(
System.Action<UnionTypesDemo.Success> onSuccess,
System.Action<UnionTypesDemo.ValidationError> onValidationError)
{
switch(this.__tag)
{
case __Tag.Success:
{
onSuccess.Invoke(((UnionTypesDemo.Success)this.__reference!));
return;
}
case __Tag.ValidationError:
{
onValidationError.Invoke(((UnionTypesDemo.ValidationError)this.__reference!));
return;
}
default:
{
throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.");
}
}
}
#endregion
#region Match
/// <summary>
/// Invokes a projection based on the type of value being represented.
/// </summary>
/// <param name="onSuccess">
/// The projection to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.Success"/>.
/// </param>
/// <param name="onValidationError">
/// The projection to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
/// </param>
/// <typeparam name="TMatchResult">
/// The type of value produced by the projections passed.
/// </typeparam>
/// <returns>
/// The projected value.
/// </returns>
public TMatchResult Match<TMatchResult>(
System.Func<UnionTypesDemo.Success, TMatchResult> onSuccess,
System.Func<UnionTypesDemo.ValidationError, TMatchResult> onValidationError) =>
this.__tag switch
{
__Tag.Success => onSuccess.Invoke(((UnionTypesDemo.Success)this.__reference!))
,
__Tag.ValidationError => onValidationError.Invoke(((UnionTypesDemo.ValidationError)this.__reference!))
,
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
#endregion
#region Represented Type
/// <summary>
/// Gets the types of value this union type can represent.
/// </summary>
public static System.Collections.Generic.IReadOnlyCollection<System.Type> RepresentableTypes { get; } =
UnionTypesDemo_ResultSave_ScopedData.RepresentableTypes;
/// <summary>
/// Gets the type of value represented by this instance.
/// </summary>
public System.Type RepresentedType =>
this.__tag switch
{
__Tag.Success => typeof(UnionTypesDemo.Success),
__Tag.ValidationError => typeof(UnionTypesDemo.ValidationError),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
#endregion
#region Is/As Properties
/// <summary>
/// Gets a value indicating whether this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>.
/// </summary>
public System.Boolean IsSuccess => __tag == __Tag.Success;
/// <summary>
/// Gets a value indicating whether this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
public System.Boolean IsValidationError => __tag == __Tag.ValidationError;
/// <summary>
/// Retrieves the value represented by this instance as a <see cref="UnionTypesDemo.Success"/>.
/// </summary>
public UnionTypesDemo.Success? AsSuccess => __tag == __Tag.Success
? ((UnionTypesDemo.Success)this.__reference!)
: null;
/// <summary>
/// Retrieves the value represented by this instance as a <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
public UnionTypesDemo.ValidationError? AsValidationError => __tag == __Tag.ValidationError
? ((UnionTypesDemo.ValidationError)this.__reference!)
: null;
#endregion
#region Is Group Properties
#endregion
#region Is/As Functions
/// <summary>
/// Determines whether this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>.
/// </summary>
/// <returns>
/// <see langword="true"/> if this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>; otherwise, <see langword="false"/>.
/// </returns>
/// <param name="value">
/// If this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>, this parameter will contain that value; otherwise, <see langword="default"/>.
/// </param>
public System.Boolean TryAsSuccess([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out UnionTypesDemo.Success value)
{
if(this.__tag == __Tag.Success)
{
value = ((UnionTypesDemo.Success)this.__reference!);
return true;
}
value = default;
return false;
}
/// <summary>
/// Determines whether this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
/// <returns>
/// <see langword="true"/> if this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>; otherwise, <see langword="false"/>.
/// </returns>
/// <param name="value">
/// If this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>, this parameter will contain that value; otherwise, <see langword="default"/>.
/// </param>
public System.Boolean TryAsValidationError([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out UnionTypesDemo.ValidationError value)
{
if(this.__tag == __Tag.ValidationError)
{
value = ((UnionTypesDemo.ValidationError)this.__reference!);
return true;
}
value = default;
return false;
}
/// <summary>
/// Determines whether this instance is representing a value of type <typeparamref name="TValue"/>.
/// </summary>
/// <typeparam name="TValue">
/// The type whose representation in this instance to determine.
/// </typeparam>
/// <returns>
/// <see langword="true"/> if this instance is representing a value of type <typeparamref name="TValue"/>; otherwise, <see langword="false"/>.
/// </returns>
public System.Boolean Is<TValue>() =>typeof(TValue) ==this.__tag switch
{
__Tag.Success => typeof(UnionTypesDemo.Success),
__Tag.ValidationError => typeof(UnionTypesDemo.ValidationError),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
/// <summary>
/// Determines whether this instance is representing a value of type <typeparamref name="TValue"/>.
/// </summary>
/// <param name="value">
/// If this instance is representing a value of type <typeparamref name="TValue"/>, this parameter will contain that value; otherwise, <see langword="default"/>.
/// </param>
/// <typeparam name="TValue">
/// The type whose representation in this instance to determine.
/// </typeparam>
/// <returns>
/// <see langword="true"/> if this instance is representing a value of type <typeparamref name="TValue"/>; otherwise, <see langword="false"/>.
/// </returns>
public System.Boolean Is<TValue>(out TValue? value)
{
var metadataName = RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.GetFullString(typeof(TValue));
switch(metadataName)
{
case "UnionTypesDemo.Success":
{
value = (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.Success, TValue>((UnionTypesDemo.Success)this.__reference!));
return true;
}
case "UnionTypesDemo.ValidationError":
{
value = (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.ValidationError, TValue>((UnionTypesDemo.ValidationError)this.__reference!));
return true;
}
default:
{
{
value = default;
return false;
}
}
}
}
/// <summary>
/// Determines whether this instance is representing an instance of <paramref name="type"/>.
/// </summary>
/// <param name="type">
/// The type whose representation in this instance to determine.
/// </param>
/// <returns>
/// <see langword="true"/> if this instance is representing an instance of <paramref name="type"/>; otherwise, <see langword="false"/>.
/// </returns>
public System.Boolean Is(System.Type type) =>
type == this.__tag switch
{
__Tag.Success => typeof(UnionTypesDemo.Success),
__Tag.ValidationError => typeof(UnionTypesDemo.ValidationError),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
/// <summary>
/// Retrieves the value represented by this instance as an instance of <typeparamref name="TValue"/>.
/// </summary>
/// <typeparam name="TValue">
/// The type to retrieve the represented value as.
/// </typeparam>
/// <returns>
/// The currently represented value as an instance of <typeparamref name="TValue"/>.
/// </returns>
public TValue As<TValue>() =>
this.__tag switch
{
__Tag.Success => typeof(TValue) == typeof(UnionTypesDemo.Success)
? (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.Success, TValue>((UnionTypesDemo.Success)this.__reference!))
: throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(UnionTypesDemo.ResultSave)} representing a value of type {this.RepresentedType} to an instance of {typeof(TValue)}."),
__Tag.ValidationError => typeof(TValue) == typeof(UnionTypesDemo.ValidationError)
? (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.ValidationError, TValue>((UnionTypesDemo.ValidationError)this.__reference!))
: throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(UnionTypesDemo.ResultSave)} representing a value of type {this.RepresentedType} to an instance of {typeof(TValue)}."),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
#endregion
#region ToString
/// <inheritdoc/>
public override System.String ToString()
{
var stringRepresentation = this.__tag switch
{
__Tag.Success => ((this.__reference!)?.ToString() ?? System.String.Empty),
__Tag.ValidationError => ((this.__reference!)?.ToString() ?? System.String.Empty),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
var result = $"ResultSave({(__tag == __Tag.Success ? "<Success>" : "Success")}|{(__tag == __Tag.ValidationError ? "<ValidationError>" : "ValidationError")}){{{stringRepresentation}}}";
return result;
}
#endregion
#region GetHashCode
/// <inheritdoc/>
public override System.Int32 GetHashCode() =>
this.__tag switch
{
__Tag.Success => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.Success>.Default.GetHashCode(((UnionTypesDemo.Success)this.__reference!))),
__Tag.ValidationError => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.ValidationError>.Default.GetHashCode(((UnionTypesDemo.ValidationError)this.__reference!))),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
#endregion
#region Equality
/// <inheritdoc/>
public override System.Boolean Equals(System.Object? obj) =>
obj is ResultSave union && Equals(union);
/// <inheritdoc/>
public System.Boolean Equals(ResultSave? other) =>
ReferenceEquals(other, this)
|| other != null
&& this.__tag == other.__tag
&& this.__tag switch
{
__Tag.Success => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.Success>.Default.Equals(((UnionTypesDemo.Success)this.__reference!), ((UnionTypesDemo.Success)other.__reference!))),
__Tag.ValidationError => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.ValidationError>.Default.Equals(((UnionTypesDemo.ValidationError)this.__reference!), ((UnionTypesDemo.ValidationError)other.__reference!))),
_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
}
;
#endregion
#region Conversions
#region Representable Type Conversions
/// <summary>
/// Converts an instance of the representable type <see cref="UnionTypesDemo.Success"/> to the union type <see cref="UnionTypesDemo.ResultSave"/>.
/// </summary>
/// <param name="value">
/// The value to convert.
/// </param>
/// <returns>
/// The union type instance.
/// </returns>
public static implicit operator ResultSave(UnionTypesDemo.Success value) => CreateFromSuccess(value);
/// <summary>
/// Converts an instance of the union type <see cref="UnionTypesDemo.ResultSave"/> to the representable type <see cref="UnionTypesDemo.Success"/>.
/// </summary>
/// <param name="union">
/// The union to convert.
/// </param>
/// <returns>
/// The represented value.
/// </returns>
public static explicit operator UnionTypesDemo.Success(UnionTypesDemo.ResultSave union) =>union.__tag == __Tag.Success?
((UnionTypesDemo.Success)union.__reference!):throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(ResultSave)} representing a value of type {union.RepresentedType} to an instance of {typeof(UnionTypesDemo.Success)}.");
/// <summary>
/// Converts an instance of the representable type <see cref="UnionTypesDemo.ValidationError"/> to the union type <see cref="UnionTypesDemo.ResultSave"/>.
/// </summary>
/// <param name="value">
/// The value to convert.
/// </param>
/// <returns>
/// The union type instance.
/// </returns>
public static implicit operator ResultSave(UnionTypesDemo.ValidationError value) => CreateFromValidationError(value);
/// <summary>
/// Converts an instance of the union type <see cref="UnionTypesDemo.ResultSave"/> to the representable type <see cref="UnionTypesDemo.ValidationError"/>.
/// </summary>
/// <param name="union">
/// The union to convert.
/// </param>
/// <returns>
/// The represented value.
/// </returns>
public static explicit operator UnionTypesDemo.ValidationError(UnionTypesDemo.ResultSave union) =>union.__tag == __Tag.ValidationError?
((UnionTypesDemo.ValidationError)union.__reference!):throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(ResultSave)} representing a value of type {union.RepresentedType} to an instance of {typeof(UnionTypesDemo.ValidationError)}.");
#endregion
#region Related Type Conversions
#endregion
#endregion
}
}
#endregion
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/UnionsGenerator