Question

The following source works as expected when using .NET inside Visual Studio, but it throws the aforementioned exception when using the Mono framework:

class Foo<TEnum> where TEnum : struct {

    private static Func<int, int> Identity = (value) => value;
    private static Func<int, TEnum> IntToEnum = Delegate.CreateDelegate(typeof(Func<int, TEnum>), Identity.Method) as Func<int, TEnum>;
    private static Func<TEnum, int> EnumToInt = Delegate.CreateDelegate(typeof(Func<TEnum, int>), Identity.Method) as Func<TEnum, int>;

    public static bool EnumEquals(TEnum lhs, TEnum rhs) {
        return EnumToInt(lhs) == EnumToInt(rhs);
    }

}

Foo<SomeEnum>.EnumEquals(SomeEnum.A, SomeEnum.B);

Is there a workaround to this which, like above, avoids boxing/unboxing values?

I am stuck with the Mono implementation which resides inside Unity :/

The Exception

ArgumentException: method return type is incompatible
System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System/Delegate.cs:190)
System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System/Delegate.cs:291)
System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System/Delegate.cs:295)
Foo`1[SomeEnum]..cctor ()
...
Was it helpful?

Solution

Well, I do not entirely understand the following, but it seems to work for both .NET and Mono and it doesn't allocate. Any comments on caveats or reliability would be appreciated!

This was adapted from here (the only difference is that Expression.Parameter requires a second parameter to please the version of Mono which is used by Unity.

internal static class CastTo<T> {
    public static T From<S>(S s) {
        return Cache<S>.caster(s);
    }

    static class Cache<S> {
        internal static readonly Func<S, T> caster = Get();

        static Func<S, T> Get() {
            var p = Expression.Parameter(typeof(S), "S");
            var c = Expression.ConvertChecked(p, typeof(T));
            return Expression.Lambda<Func<S, T>>(c, p).Compile();
        }
    }
}

Which can then be used as follows:

public enum Example {
    A,
    B,
    C,
}

long example = CastTo<long>.From<Example>(Example.B);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top