Let’s look at an extreme example, where the object we use has a
type
created at run time:
class BaseClass {
public virtual string SayHello() {
return "Hello from base!";
class GenericDerivedClass<T> : BaseClass {
public override string SayHello() {
return "Hello from derived!";
}
Given these types, we can try this code in Unity (I’m using version 5.3.5):
public class VirtualInvokeExample : MonoBehaviour {
void Start () {
Debug.Log(MakeRuntimeBaseClass().SayHello());
private BaseClass MakeRuntimeBaseClass() {
var derivedType = typeof(GenericDerivedClass<>).MakeGenericType(typeof(int));
return (BaseClass)FormatterServices.GetUninitializedObject(derivedType);
}
The details of MakeRuntimeBaseClass are not too important. What really matters is the object it creates has a type (GenericDerivedClass<int>) which is created at run time.
This somewhat odd code is no problem for a Just-in-time (JIT) compiler, where the compilation work happens at runtime. If we run it in the Unity editor, we get:
Hello from derived!
UnityEngine.Debug:Log(Object)
VirtualInvokeExample:Start() (at Assets/VirtualInvokeExample.cs:7)
But the story is quite different with an Ahead-of-time (AOT) compiler. If we run this same code for iOS with IL2CPP, we get this exception:
ExecutionEngineException: Attempting to call method 'GenericDerivedClass`1[[System.Int32, mscorlib, Version=2.0.5.0,
Culture=, PublicKeyToken=7cec85d7bea7798e]]::SayHello' for which no ahead of time (AOT) code was generated.
at VirtualInvokeExample.Start () [0x00000] in <filename unknown>:0
That type created at runtime (GenericDerivedType<int>) is causing problems for the SayHello virtual method call. Since IL2CPP is an AOT compiler, and there is no source code for the GenericDerivedType<int> type, IL2CPP did not generate an implementation of the SayHello method.