在构建到 UWP 和 Il2CPP 之后,通用方法中的 AOT(提前)出现问题
Problem with AOT (ahead of time) in a generic method after built to UWP and Il2CPP
我有一个通用方法,可以尝试使用我自己的 TryGetValue
之类的键通过字典从字典中获取通用值(当然,对基本内容进行了很多裁剪)
public class BaseExample
{
public virtual bool TryGetValue<T>(string key, out T value)
{
value = default;
return false;
}
}
public class Example : BaseExample
{
private Dictionary<string, Item> _items = new Dictionary<string, Item>();
public override bool TryGetValue<T>(string key, out T value)
{
value = default;
if (!GetItem(key, value, out var setting)) { return false; }
value = (T)setting.Value;
return true;
}
private bool GetItem<T>(string key, T value, out Item item)
{
item = null;
if (!_items.ContainsKey(key))
{
item = null;
return false;
}
item = _items[key];
return true;
}
}
这在 Unity 编辑器中有效,但一旦我尝试 运行 使用
方法将其构建到 UWP 和 IL2CPP
var value = example.TryGetValue<int>("SomeKey");
它抛出一个
System.ExecutionEngineException: Attempting to call method 'Example::TryGetValue<System.Int32>' for which no ahead of time (AOT) code was generated.
这可能是什么原因,我该如何解决?
好的,经过进一步的研究和测试,得出的结论如下:
由于 according 方法是接口的一部分,并且只能通过接口或基础 class 调用,因此从未通过此 class.[=13 显式调用 Example.TryGetValue
方法=]
由于 Example
class 位于与接口和 Base class 不同的程序集中,因此 Example.TryGetValue
的代码在编译时以某种方式被删除(因为编译器认为它永远不会被使用),因此在构建的后期丢失。
我现在知道原因以及未来需要注意什么,但还没有真正的解决方案,除非有一个明确的实现并调用它,这样它就不会被剥夺...
要解决这样的 AOT 问题,您可以强制编译器生成正确的代码。您可以在 class 中添加以下示例方法:
public void UsedOnlyForAOTCodeGeneration()
{
// YOUR CODE HERE
// Include an exception so we can be sure to know if this method is ever called.
throw new InvalidOperationException(@"This method is used for AOT code generation only.
Do not call it at runtime.");
}
对于我的具体情况(如果它对任何人有帮助)我使用的是
WrapperMethod<WeatherFrameInfo[]>();
WrapperMethod<T>() {
JsonConvert.DeserializeObject<T>(json);
}
导致错误的原因:
2022/03/17 14:53:32.888 13468 13524 Error Unity ExecutionEngineException: Attempting to call method 'System.Collections.Generic.List`1[[WeatherFrameInfo, ScriptsAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]::.cctor' for which no ahead of time (AOT) code was generated.
2022/03/17 14:53:32.888 13468 13524 Error Unity at System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object[] parameters, System.Boolean wrapExceptions) [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtonsoft.Json.Utilities.LateBoundReflectionDelegateFactory+<>c__DisplayClass5_0`1[T].<CreateDefaultConstructor>b__1 () [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtonsoft.Json.Serialization.JsonArrayContract.CreateTemporaryCollection () [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewList (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonArrayContract contract, System.Boolean& createdFromNonDefaultCreator) [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtons
我推测 Newtonsoft 会在某个时候将我的数组输入转换为 List
,所以我重构了我的代码以提前 和中提琴
WrapperMethod<List<WeatherFrameInfo>>();
WrapperMethod<T>() {
JsonConvert.DeserializeObject<T>(json);
}
我有一个通用方法,可以尝试使用我自己的 TryGetValue
之类的键通过字典从字典中获取通用值(当然,对基本内容进行了很多裁剪)
public class BaseExample
{
public virtual bool TryGetValue<T>(string key, out T value)
{
value = default;
return false;
}
}
public class Example : BaseExample
{
private Dictionary<string, Item> _items = new Dictionary<string, Item>();
public override bool TryGetValue<T>(string key, out T value)
{
value = default;
if (!GetItem(key, value, out var setting)) { return false; }
value = (T)setting.Value;
return true;
}
private bool GetItem<T>(string key, T value, out Item item)
{
item = null;
if (!_items.ContainsKey(key))
{
item = null;
return false;
}
item = _items[key];
return true;
}
}
这在 Unity 编辑器中有效,但一旦我尝试 运行 使用
方法将其构建到 UWP 和 IL2CPPvar value = example.TryGetValue<int>("SomeKey");
它抛出一个
System.ExecutionEngineException: Attempting to call method 'Example::TryGetValue<System.Int32>' for which no ahead of time (AOT) code was generated.
这可能是什么原因,我该如何解决?
好的,经过进一步的研究和测试,得出的结论如下:
由于 according 方法是接口的一部分,并且只能通过接口或基础 class 调用,因此从未通过此 class.[=13 显式调用 Example.TryGetValue
方法=]
由于 Example
class 位于与接口和 Base class 不同的程序集中,因此 Example.TryGetValue
的代码在编译时以某种方式被删除(因为编译器认为它永远不会被使用),因此在构建的后期丢失。
我现在知道原因以及未来需要注意什么,但还没有真正的解决方案,除非有一个明确的实现并调用它,这样它就不会被剥夺...
要解决这样的 AOT 问题,您可以强制编译器生成正确的代码。您可以在 class 中添加以下示例方法:
public void UsedOnlyForAOTCodeGeneration()
{
// YOUR CODE HERE
// Include an exception so we can be sure to know if this method is ever called.
throw new InvalidOperationException(@"This method is used for AOT code generation only.
Do not call it at runtime.");
}
对于我的具体情况(如果它对任何人有帮助)我使用的是
WrapperMethod<WeatherFrameInfo[]>();
WrapperMethod<T>() {
JsonConvert.DeserializeObject<T>(json);
}
导致错误的原因:
2022/03/17 14:53:32.888 13468 13524 Error Unity ExecutionEngineException: Attempting to call method 'System.Collections.Generic.List`1[[WeatherFrameInfo, ScriptsAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]::.cctor' for which no ahead of time (AOT) code was generated.
2022/03/17 14:53:32.888 13468 13524 Error Unity at System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object[] parameters, System.Boolean wrapExceptions) [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtonsoft.Json.Utilities.LateBoundReflectionDelegateFactory+<>c__DisplayClass5_0`1[T].<CreateDefaultConstructor>b__1 () [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtonsoft.Json.Serialization.JsonArrayContract.CreateTemporaryCollection () [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewList (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonArrayContract contract, System.Boolean& createdFromNonDefaultCreator) [0x00000] in <00000000000000000000000000000000>:0
2022/03/17 14:53:32.888 13468 13524 Error Unity at Newtons
我推测 Newtonsoft 会在某个时候将我的数组输入转换为 List
,所以我重构了我的代码以提前 和中提琴
WrapperMethod<List<WeatherFrameInfo>>();
WrapperMethod<T>() {
JsonConvert.DeserializeObject<T>(json);
}