This question is specifically about Unity3d IL2CPP and iOS.
Calling a generic method using reflection
class SourceValue<T> { public T value; }
class TargetValue<T> { public T value; }
static TargetValue<T> GenericMethod<T> (SourceValue<T> source) {
return new TargetValue<T> { value = source.value };
}
void Main () {
Type genericType = typeof(SourceValue<float>);
Type typeArg = genericType.GenericTypeArguments[0];
MethodInfo mi = GetType ().GetMethod ("GenericMethod", Flags | BindingFlags.Static);
MethodInfo gmi = mi.MakeGenericMethod (typeArg);
object src = new SourceValue<float> { value = 0.5f };
object trg = gmi.Invoke (this, new object[] { src });
}
This works as expected when run in the Unity editor on mac. The invocation fails on iOS with error:
ExecutionEngineException: Attempting to call method 'GenericMethod<System.Single>' for which no ahead of time (AOT) code was generated.
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0
Is it simply that the AOT system can't call generic methods or am i missing something?
Yes, since IL2CPP is an ahead-of-time (AOT) compiler, it only works for code that exists at compile time. No code here uses GenericMethod<float>
in "real" C# source code, so IL2CPP does not know to generate the corresponding code to make that implementation work.
The real restriction here is that the generic argument type is float
, which is a value type. You could use string
(a reference type) in this case without any problems. IL2CPP shares the implementation of all generic types that have a generic argument which is a reference type (e.g. string
, object
, etc.). This is possible because all reference types in C# are the same size (IntrPtr.Size
, to be exact).
So the limitation here is really two-fold:
Note that it is theoretically possible for IL2CPP to also share the implementation of generic types with value type generic arguments, although that has not yet been implemented.
EDIT: As of Unity 2022.2 this has been implemented - ExecutionEngineException
will not longer happen, and the original scenario will work.