RSCG – UnionsGenerator
RSCG – UnionsGenerator
name | UnionsGenerator |
nuget | https://www.nuget.org/packages/RhoMicro.CodeAnalysis.UnionsGenerator |
link | https://github.com/PaulBraetz/RhoMicro.CodeAnalysis/ |
author | Paul Braetz |
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
Leave a Reply