How to mimick the compiler type cast in runtime

1 day ago 1
ARTICLE AD BOX

What I am trying to do

I need to perform implicit and explicit type casts at runtime (using Reflection) for basic types and other types that may exist in the code (known at compile time), including classes, structs, and enums. I want to mimick the compiler. It needs to be compatible with Unity, at least version 6, which means some new features are not present.

I'm doing workarounds that are not the exact the compiler would do. I would love if the framework could resolve these type casts for me, instead of searching through reflection manually.

My question

I am searching for ways to force compiler discover the type and do what it would usually do in compile time. For example:

public TOut Convert<TIn, TOut>(TIn value) => (TOut)value;

This obviously results in a compilation error, because TIn and TOut are not compatible.

However, Convert<float, int>(10f) can be known at compile time or via MakeGeneric, and would be possible to some extent. Although there are scenarios where it wouldn’t be possible (e.g. Convert<Enum, Array>). Then the compiler does not allow that.

Is there any way to make this work? A rule, perhaps? An interface? Other approach?

What I've done so far

Convert.ChangeType requires IConvertible. Not what I want.

public T Implicit<T>(dynamic value) => value; public T Explicit<T>(dynamic value) => (T)value; is the best option so far.
It works, except for null objects: where compiler (int)(MyType)(null) calls the op_Explicit overload, Explicit<int>(default(MyType)) does not work because null has no type. I did not find other problems.

Currently, I look for op_Implicit and op_Explicit methods in the type using GetMethods or GetMember, then I filter the list by the parameters. Sadly, Numerics interfaces are not available for primitive values in my version of the framework, then I cannot rely in this approach for primitive types. I've built a manual list of possible type casts with lamdas resolving type at compile time. Again, it works but I've chosen only 7 primitives because of size of the class, then it is not exactly what compiler would do. And there is a classe with all the pairs (int→long, int→float, int→double, long→float, long→double, float→double, etc.)

I have searched several posts (ex.: this answer from Jon Skeet, which helped with dynamic).

Read Entire Article