You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity安卓端访问表达式体属性崩溃但编辑器正常问题

Unity安卓AOT编译下表达式体属性访问崩溃的解决办法

问题场景

我有一个继承自MonoBehaviour的C#单例类,首次访问时会自动创建GameObject并实例化自身:

public class MyClass : MonoBehaviour {

  private static MyClass _Instance;
  public static MyClass Instance {
    get {
      if (!_Instance) {
        _Instance = new GameObject().AddComponent<MyClass>();
        _Instance.name = _Instance.GetType().ToString();
        DontDestroyOnLoad(_Instance.gameObject);
      }
      return _Instance;
    }
  }

 public string SomeFunction() { return "Hello world"; }
 public string SomeArrow => "Good morning moon";
}

在其他脚本中访问表达式体成员Debug.Log(MyClass.Instance.SomeArrow);时,安卓编译后的应用出现静默崩溃:游戏帧仍在运行、UI可交互,但所有C#代码停止执行。LogCat报错:

ExecutionEngineException attempting to call method system.Linq.Expressions.Interpreter.LightLambda::MakeRun2<System.Runtime.CompilerServices.CallSite,System.Object,System.Int32 for which no ahead of time (AOT) code was generated.

该问题仅在安卓编译后出现,Unity编辑器中运行正常。改用普通函数Debug.Log(MyClass.Instance.SomeFunction());可正常运行,但因需暴露大量存储在Dictionary<string, string>中的缓存数据并转换类型,无法大量创建公共变量替代。类内部访问表达式体属性无异常,仅外部访问实例化对象的该属性时崩溃。使用Unity版本:2021.3.8.f1

原因分析

Unity安卓平台默认使用IL2CPP进行AOT(提前编译),表达式体属性(=>语法)在部分场景下会触发.NET的动态代码生成逻辑(比如通过CallSite进行动态调用),而AOT编译环境无法提前生成这些动态代码,导致运行时抛出ExecutionEngineException并引发崩溃。编辑器采用JIT(即时编译),可以动态生成代码,因此不会出现问题。

解决办法

1. 替换表达式体属性为普通getter属性

把所有表达式体属性改成显式的get方法实现,避免触发动态代码生成:

// 原表达式体属性
public string SomeArrow => "Good morning moon";

// 改为普通getter属性
public string SomeArrow {
  get {
    return "Good morning moon";
  }
}

2. 针对Dictionary缓存数据的批量处理方案

如果需要暴露大量Dictionary中的缓存并转换类型,不要用表达式体属性,改用以下两种方式减少重复代码:

显式getter示例(针对单个类型转换)

private Dictionary<string, string> _cache = new Dictionary<string, string>();

public int PlayerLevel {
  get {
    return int.TryParse(_cache["PlayerLevel"], out int level) ? level : 0;
  }
}

public float PlayerHealth {
  get {
    return float.TryParse(_cache["PlayerHealth"], out float health) ? health : 0f;
  }
}

通用方法示例(适配多类型转换)

public T GetCachedValue<T>(string key) where T : IConvertible {
  if (_cache.TryGetValue(key, out string value)) {
    try {
      return (T)Convert.ChangeType(value, typeof(T));
    }
    catch {
      // 按需处理转换失败的情况
      return default;
    }
  }
  return default;
}

调用示例:Debug.Log(MyClass.Instance.GetCachedValue<int>("PlayerLevel"));

内容的提问来源于stack exchange,提问作者Rasmus Puls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:21:59