在iOS上的C# IL2CPP中通过反射调用泛型方法

bvuwiixz  于 2023-05-30  发布在  iOS
关注(0)|答案(1)|浏览(215)

这个问题是关于Unity3d IL2CPP和iOS的。
使用反射调用泛型方法

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 });
}

当在Mac上的Unity编辑器中运行时,它会按照预期工作。在iOS上调用失败,错误为:

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

仅仅是因为AOT系统不能调用泛型方法,还是我遗漏了什么?

mutmk8jj

mutmk8jj1#

是的,因为IL 2CPP是一个超前(AOT)编译器,它只适用于编译时存在的代码。这里没有代码在“真实的的”C#源代码中使用GenericMethod<float>,所以IL 2CPP不知道生成相应的代码来使该实现工作。
这里真实的的限制是泛型参数类型是float,这是一种值类型。在这种情况下,您可以使用string(一种引用类型),没有任何问题。IL 2CPP共享所有泛型类型的实现,这些泛型类型具有泛型参数,该泛型参数是引用类型(例如stringobject等)。这是可能的,因为C#中的所有引用类型都是相同的大小(IntrPtr.Size,确切地说)。
所以这里的限制实际上是双重的:

  1. IL 2CPP只能在编译时生成已知的代码
    1.此限制仅适用于类型参数为值类型时的泛型类型。
    请注意,IL 2CPP理论上也可以使用值类型泛型参数共享泛型类型的实现,尽管这还没有实现。
    编辑:从Unity 2022.2开始,这已经实现了-ExecutionEngineException将不再发生,并且原始场景将工作。

相关问题