[Unity]ボックス化しないジェネリックなEnumのHasFlag

#コード
```C#:Cast.cs
public static class Cast<T>
{
	private static class Cache<S>
	{
		static Cache()
		{
			var p = Expression.Parameter(typeof(S));
			var c = Expression.ConvertChecked(p, typeof(T));
			Caster = Expression.Lambda<Func<S, T>>(c, p).Compile();
		}
		internal static readonly Func<S, T> Caster;
	}

	public static T From<S>(S source)
	{
		return Cache<S>.Caster(source);
	}
}

```
↑引用元：http://csharpvbcomparer.blogspot.com/2014/09/net-cast-cheats-compiler.html

```C#:HasFlag.cs
public static bool HasFlagNoBoxing<T>(this T value, T flag) where T : struct, Enum
{	
	var intValue = Cast<int>.From(value);
	var intFlagValue = Cast<int>.From(flag);
	return (intValue & intFlagValue) != 0;
}
```
#パフォーマンス
```C#:計測コード.cs
[Flags]
public enum Number : int
{
	One = 1,
	Two = 1 << 1,
	Three = 1 << 2,
	Four = 1 << 3,
	Five = 1 << 4,
}

var values = Enum.GetValues(typeof(Number)) as Number[];
Number result = default;
var count = 100000;


Profiler.BeginSample(Generic);
for (int i = 0; i < count; i++)
{
	if (values[i % values.Length].HasFlagNoBoxing(Number.One | Number.Five))
	{
		result |= values[i % values.Length];
	}
}
Profiler.EndSample();
```
初回はCompile()のせいでめちゃくちゃ重い
![HasFlag.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253279/03ecb2c6-3406-999c-424f-21b1fe845df9.jpeg)
キャッシュされていれば使えなくも無い程度、調べてないけどiOSとかだと実行時にたぶん死ぬ
![hasflag2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253279/ea4efc3c-dfed-f5f5-847c-8455fd782600.jpeg)

下記のコードはプロファイラ表示のConfrimedTypeMethodで、計測するとだいたい3倍くらい早いので
正直テンプレートかスニペットで用意するのが楽そう

```C#:Extentions.cs
public static class NumberExtention
{
	public static bool HasFlagNoBoxing(this Number value, Number flag)
	{
		return (value & flag) != 0;
	}
}
```
#試したけど駄目だったやつ
構造体でも制約指定してさえいればBox化せずにInterfaceを使えるのでいけるかと思いきや
Enumはだめで普通にIConvertible型に変換されてボックス化しました

```C#:Extentions.cs
public static bool hogehoge<T>(this T value,T flag) where T: struct, Enum, IConvertible
{
	var intValue = value.ToInt32(null);
	var intFlagValue = flag.ToInt32(null);
	return (intValue & intFlagValue) != 0;
}


```

enumの基底にintを指定しても変換できず全部false

```C#:Extentions.cs
public static bool hogehoge<T>(this T value, T flag) where T : struct, Enum
{
	if (value is int intValue && flag is int intFlagValue)
	{
		return (intValue & intFlagValue) != 0;
	}
	return false;
}
```

これでintに変換して判定しようとしたが
ジェネリックでLayoutKind.Explicitは例外を吐いて使用できず終了

```C#:FastEnumConvert.cs
[StructLayout(LayoutKind.Explicit)]
struct FastEnumConverter<T> where T : IConvertible
{
    [FieldOffset(0)] public T Raw;
    [FieldOffset(0)] public sbyte AsSByte;
    [FieldOffset(0)] public byte AsByte;
    [FieldOffset(0)] public short AsShort;
    [FieldOffset(0)] public ushort AsUShort;
    [FieldOffset(0)] public int AsInt;
    [FieldOffset(0)] public uint AsUInt;
    [FieldOffset(0)] public long AsLong;
    [FieldOffset(0)] public ulong AsULong;
}
 
public static class FastEnumConvert
{
    public static sbyte ToSByte<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsSByte; }
    public static byte ToByte<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsByte; }
    public static short ToShort<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsShort; }
    public static ushort ToUShort<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsUShort; }
    public static int ToInt32<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsInt; }
    public static uint ToUInt32<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsUInt; }
    public static long ToLong<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsLong; }
    public static ulong ToULong<T>(T value) where T : IConvertible { return new FastEnumConverter<T> { Raw = value }.AsULong; }
 
    public static T ToEnum<T>(sbyte value) where T : IConvertible { return new FastEnumConverter<T> { AsSByte = value }.Raw; }
    public static T ToEnum<T>(byte value) where T : IConvertible { return new FastEnumConverter<T> { AsByte = value }.Raw; }
    public static T ToEnum<T>(short value) where T : IConvertible { return new FastEnumConverter<T> { AsShort = value }.Raw; }
    public static T ToEnum<T>(ushort value) where T : IConvertible { return new FastEnumConverter<T> { AsUShort = value }.Raw; }
    public static T ToEnum<T>(int value) where T : IConvertible { return new FastEnumConverter<T> { AsInt = value }.Raw; }
    public static T ToEnum<T>(uint value) where T : IConvertible { return new FastEnumConverter<T> { AsUInt = value }.Raw; }
    public static T ToEnum<T>(long value) where T : IConvertible { return new FastEnumConverter<T> { AsLong = value }.Raw; }
    public static T ToEnum<T>(ulong value) where T : IConvertible { return new FastEnumConverter<T> { AsULong = value }.Raw; }
}
```

↑引用元http://baba-s.hatenablog.com/entry/2017/12/27/210400