private static void AppendMethod_Set(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            foreach (var member in def.Members)
            {
                builder.Append($@"
        public void Set({member.Type} value)
        {{
            this.{pre_}ValueType = Type.{member.Name};
            this.{pre_}{member.Name} = value;
        }}
");
            }
        }
        private static void AppendMethod_GetUnderlyingType(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public System.Type GetUnderlyingType()");

            if (def.Members.Count < 3)
            {
                builder.Append(@"
        {");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (this.{pre_}ValueType == Type.{member.Name})
                return this.{pre_}{member.Name}.GetType();
");
                }

                builder.Append(@"
            return this.GetType();
        }
");
            }
            else
            {
                builder.Append($@"
        {{
            switch (this.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return this.{pre_}{member.Name}.GetType();");
                }

                builder.Append(@"
            }

            return this.GetType();
        }
");
            }
        }
        private static void AppendMethod_GetHashCode(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public override int GetHashCode()
        {{
            var hash = EqualityComparer<Type>.Default.GetHashCode(this.{pre_}ValueType) * -1521134295;
");

            if (def.Members.Count < 3)
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (this.{pre_}ValueType == Type.{member.Name})
                return hash + EqualityComparer<{member.Type}>.Default.GetHashCode(this.{pre_}{member.Name});
");
                }

                builder.Append(@"
            return hash;
        }
");
            }
            else
            {
                builder.Append($@"
            switch (this.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return hash + EqualityComparer<{member.Type}>.Default.GetHashCode(this.{pre_}{member.Name});");
                }

                builder.Append(@"
            }

            return hash;
        }
");
            }
        }
        private static void AppendConstructors(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();
            var last = def.Members.Count - 1;

            for (var i = 0; i < def.Members.Count; i++)
            {
                var member = def.Members[i];

                if (i > 0)
                {
                    builder.AppendLine();
                }

                builder.Append($@"
        public {def.Name}({member.Type} value)
        {{
            this.{pre_}ValueType = Type.{member.Name};
");

                for (var k = 0; k < def.Members.Count; k++)
                {
                    if (k == i)
                    {
                        continue;
                    }

                    var memberOther = def.Members[k];

                    builder.Append($@"
            this.{pre_}{memberOther.Name} = default;");
                }

                builder.Append($@"

            this.{pre_}{member.Name} = value;
        }}");

                if (i == last)
                {
                    builder.AppendLine();
                }
            }
        }
        private static void AppendConstructorTypeParam(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public {def.Name}(Type type)
        {{
            this.{pre_}ValueType = type;
");

            foreach (var member in def.Members)
            {
                builder.Append($@"
            this.{pre_}{member.Name} = default;");
            }

            builder.Append(@"
        }
");
        }
        private static void AppendMethod_ToString(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append(@"
        public override string ToString()
        {");

            if (def.Members.Count < 3)
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (this.{pre_}ValueType == Type.{member.Name})
                return this.{pre_}{member.Name}.ToString();
");
                }

                builder.Append(@"
            return string.Empty;
        }");
            }
            else
            {
                builder.Append($@"
            switch (this.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return this.{pre_}{member.Name}.ToString();");
                }

                builder.Append(@"
            }

            return string.Empty;
        }");
            }
        }
        private static void AppendMethod_TryGet(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            foreach (var member in def.Members)
            {
                builder.Append($@"
        public bool TryGet(out {member.Type} value)
        {{
            if (this.{pre_}ValueType != Type.{member.Name})
            {{
                value = default;
                return false;
            }}

            value = this.{pre_}{member.Name};
            return true;
        }}
");
            }
        }
        private static void AppendOperator_Implicit(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();
            var last = def.Members.Count - 1;

            switch (def.InvalidValueAccess)
            {
            case InvalidValueAccess.ThrowException:
            {
                for (var i = 0; i < def.Members.Count; i++)
                {
                    var member = def.Members[i];

                    if (i <= 0)
                    {
                        builder.AppendLine();
                    }

                    builder.Append($@"
        public static implicit operator {def.Name}({member.Type} value)
            => new {def.Name}(value);
");

                    builder.Append($@"
        public static implicit operator {member.Type}(in {def.Name} value)
        {{
            if (value.{pre_}ValueType == Type.{member.Name})
                return value.{pre_}{member.Name};

            throw new InvalidValueAccessException($""Cannot implicitly convert underlying type '{{value.GetUnderlyingType().GetNiceFullName()}}' to '{member.Type}'"");
        }}");

                    if (i < last)
                    {
                        builder.AppendLine();
                    }
                }
                break;
            }

            case InvalidValueAccess.ReturnDefault:
            {
                for (var i = 0; i < def.Members.Count; i++)
                {
                    var member = def.Members[i];

                    if (i <= 0)
                    {
                        builder.AppendLine();
                    }

                    builder.Append($@"
        public static implicit operator {def.Name}({member.Type} value)
            => new {def.Name}(value);
");

                    builder.Append($@"
        public static implicit operator {member.Type}(in {def.Name} value)
        {{
            if (value.{pre_}ValueType == Type.{member.Name})
                return value.{pre_}{member.Name};

            return default;
        }}");

                    if (i < last)
                    {
                        builder.AppendLine();
                    }
                }
                break;
            }

            default:
            {
                for (var i = 0; i < def.Members.Count; i++)
                {
                    var member = def.Members[i];

                    if (i <= 0)
                    {
                        builder.AppendLine();
                    }

                    builder.Append($@"
        public static implicit operator {def.Name}({member.Type} value)
            => new {def.Name}(value);
");

                    builder.Append($@"
        public static implicit operator {member.Type}(in {def.Name} value)
            => value.{pre_}{member.Name};");

                    if (i < last)
                    {
                        builder.AppendLine();
                    }
                }
                break;
            }
            }
        }
        private static void AppendMethod_Equals(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public override bool Equals(object obj)
            => obj is {def.Name} other && Equals(in this, in other);

        public bool Equals({def.Name} other)
            => Equals(in this, in other);

        public bool Equals(in {def.Name} other)
            => Equals(in this, in other);
");

            builder.Append($@"
        public static bool Equals(in {def.Name} a, in {def.Name} b)");

            if (def.Members.Count < 3)
            {
                builder.Append($@"
        {{
            if (a.{pre_}ValueType != b.{pre_}ValueType)
                return false;
");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (a.{pre_}ValueType == Type.{member.Name})
                return EqualityComparer<{member.Type}>.Default.Equals(a.{pre_}{member.Name}, b.{pre_}{member.Name});
");
                }

                builder.Append(@"
            return false;
        }
");
            }
            else
            {
                builder.Append($@"
        {{
            if (a.{pre_}ValueType != b.{pre_}ValueType)
                return false;

            switch (a.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return EqualityComparer<{member.Type}>.Default.Equals(a.{pre_}{member.Name}, b.{pre_}{member.Name});");
                }

                builder.Append(@"
            }

            return false;
        }
");
            }

            builder.Append($@"
        public static bool operator ==(in {def.Name} left, in {def.Name} right)
            => Equals(in left, in right);

        public static bool operator !=(in {def.Name} left, in {def.Name} right)
            => !Equals(in left, in right);
");
        }