在构建到 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);
}