Skip to content

Latest commit

 

History

History
92 lines (83 loc) · 2.92 KB

2019-10-16.md

File metadata and controls

92 lines (83 loc) · 2.92 KB

Date: October 16, 2019
Original Post: https://gist.github.com/ZacharyPatten/201777593c35b11ea2d90066320113f1

C# Generic Enum Union

using System;
using System.Linq.Expressions;
using static Towel.Syntax;

namespace Example
{
	class Program
	{
		static void Main(string[] args)
		{
			// This code contains snippets from the /~https://github.com/ZacharyPatten/Towel project.
			// Please check out the project if you want to see more code like it. :)

			EnumUnion<A, B> aOrB1 = A.One;
			EnumUnion<A, B> aOrB2 = B.One;
			Console.WriteLine(aOrB1 == aOrB2);
			EnumUnion<A, B> aOrB3 = B.Three;
			Console.WriteLine(aOrB1 != aOrB3);
			EnumUnion<A, B> aOrB4 = B.NegativeOne;
			Console.WriteLine(aOrB4.Value == -1);
		}
	}

	public enum A
	{
		NegativeOne = -1,
		Zero = 0,
		One = 1,
	}

	public enum B
	{
		NegativeOne = -1,
		Zero = 0,
		One = 1,
		Two = 2,
		Three = 3,
	}

	public struct EnumUnion<A, B>
		where A : unmanaged, Enum
		where B : unmanaged, Enum
	{
		public long Value { get; internal set; }
		public EnumUnion(A a) => Value = Convert<A, long>(a);
		public EnumUnion(B b) => Value = Convert<B, long>(b);
		public static implicit operator EnumUnion<A, B>(A a) => new EnumUnion<A, B>(a);
		public static implicit operator EnumUnion<A, B>(B b) => new EnumUnion<A, B>(b);
		public static bool operator ==(EnumUnion<A, B> a, EnumUnion<A, B> b) => a.Value == b.Value;
		public static bool operator !=(EnumUnion<A, B> a, EnumUnion<A, B> b) => a.Value != b.Value;
		public static bool operator ==(EnumUnion<A, B> union, A a) => union.Value == Convert<A, long>(a);
		public static bool operator !=(EnumUnion<A, B> union, A a) => union.Value != Convert<A, long>(a);
		public static bool operator ==(A a, EnumUnion<A, B> union) => union.Value == Convert<A, long>(a);
		public static bool operator !=(A a, EnumUnion<A, B> union) => union.Value != Convert<A, long>(a);
		public static bool operator ==(EnumUnion<A, B> union, B b) => union.Value == Convert<B, long>(b);
		public static bool operator !=(EnumUnion<A, B> union, B b) => union.Value != Convert<B, long>(b);
		public static bool operator ==(B b, EnumUnion<A, B> union) => union.Value == Convert<B, long>(b);
		public static bool operator !=(B b, EnumUnion<A, B> union) => union.Value != Convert<B, long>(b);
		public override int GetHashCode() => Value.GetHashCode();
		public override bool Equals(object @object) =>
			@object is A a ? a == this :
			@object is B b ? b == this :
			@object is EnumUnion<A, B> union ? union == this :
			false;
	}
}

namespace Towel
{
	public static class Syntax
	{
		public static B Convert<A, B>(A a) => ConvertImplementation<A, B>.Function(a);

		internal static class ConvertImplementation<A, B>
		{
			internal static Func<A, B> Function = a =>
			{
				ParameterExpression A = Expression.Parameter(typeof(A));
				Expression BODY = Expression.Convert(A, typeof(B));
				Function = Expression.Lambda<Func<A, B>>(BODY, A).Compile();
				return Function(a);
			};
		}
	}
}