包含此页的版本:
不含此页的版本:
Unity 在所有受支持的平台上提供通用的脚本 API 和体验。然而,一些平台有固有的限制。下表描述了适用于每个平台和脚本后端为Unity中的脚本提供支持的框架。Unity 支持三种不同的脚本后端,具体取决于目标平台:Mono、.NET 和 IL2CPP。但是,通用 Windows 平台仅支持两个:.NET 和 IL2CPP。更多信息
请参阅术语表:
| 平台(脚本后端) | 提前编译 | 支持线程 |
|---|---|---|
| 安卓 (IL2CPP) | 是的 | 是的 |
| Android(单声道) | 不 | 是的 |
| iOS (IL2CPP) | 是的 | 是的 |
| 独立 (IL2CPP) | 是的 | 是的 |
| 独立(单声道) | 不 | 是的 |
| 通用 Windows 平台 (IL2CPP) | 是的 | 是的 |
| 网页 (IL2CPP) | 是的 | 不 |
某些平台不允许生成运行时代码。任何依赖于目标设备上的实时 (JIT) 编译的托管代码都将失败。相反,必须提前编译所有托管代码 (AOT)。通常,这种区别并不重要,但在少数特定情况下,AOT 平台需要额外考虑。
Unity 支持 AOT 平台上的反射。但是,如果编译器无法推断出代码是通过反射使用的,则代码在运行时可能不存在。有关详细信息,请参阅托管代码剥离。
AOT 平台无法实现System.Reflection.EmitNamespace。
由于使用反射,AOT 平台可能会遇到序列化和反序列化问题。如果类型或方法仅通过反射作为序列化或反序列化的一部分使用,则 AOT 编译器无法检测到它是否需要生成类型或方法所需的代码。
对于泛型类型和方法,编译器必须确定使用哪些泛型实例,因为不同的泛型实例可能需要不同的代码。例如,代码List<int>与List<double>.但是,IL2CPP 将共享引用类型的用法代码,因此相同的代码将用于List<object>和List<string>.
可以引用泛型类型和方法IL2CPP:Unity 开发的脚本后端,在为某些平台构建项目时,可以将其用作 Mono 的替代品。更多信息
请参阅术语表在以下情况下在编译时找不到:
Activator.CreateInstance(typeof(SomeGenericType<>).MakeGenericType(someType));
typeof(SomeGenericType<>).MakeGenericType(someType).GetMethod("AMethod").Invoke(null, null);
typeof(SomeType).GetMethod("GenericMethod").MakeGenericMethod(someType).Invoke(null, null);
Struct<Struct<Struct<...<Struct<int>>>>.为了支持这些情况,IL2CPP 生成适用于任何类型参数的通用代码。但是,此代码速度较慢,因为它无法确定类型的大小,或者它是引用类型还是值类型。如果需要确保生成更快的泛型方法,请执行以下作:
where: class约束。然后,IL2CPP 使用引用类型共享生成回退方法,这不会导致性能下降。where: struct约束。这启用了一些优化,但代码仍然会变慢,因为值类型可以有不同的大小。UsedOnlyForAOTCodeGeneration并添加对希望 IL2CPP 生成的泛型类型和方法的引用。永远不需要调用此方法。以下示例可确保GenericType<MyStruct>生成:public void UsedOnlyForAOTCodeGeneration()
{
// Ensure that IL2CPP will create code for MyGenericStruct
// using MyStruct as an argument.
new GenericType<MyStruct>();
// Ensure that IL2CPP will create code for SomeType.GenericMethod
// using MyStruct as an argument.
new SomeType().GenericMethod<MyStruct>();
public void OnMessage<T>(T value)
{
Debug.LogFormat("Message value: {0}", value);
}
// 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.");
}
注意:要仅编译通用代码的单个、完全可共享的版本,请将 IL2CPP 代码生成播放器设置设置为针对代码大小和构建时间进行优化。这减少了生成的方法数量,减少了编译时间和构建大小,但以牺牲运行时性能为代价。
需要封送到 C 函数指针以便可以从本机代码调用的托管方法对 AOT 平台有一些限制:
[MonoPInvokeCallback]属性。[MonoPInvokeCallback(Type)]重载以指定必须支持的通用专用化。如果是这样,则类型必须是具有正确数量的泛型参数的泛型实例。可以有多个[MonoPInvokeCallback]属性,如下所示:// Generates reverse P/Invoke wrappers for NameOf<long> and NameOf<int>
// Note that the types are only used to indicate the generic arguments.
[MonoPInvokeCallback(typeof(Action<long>))]
[MonoPInvokeCallback(typeof(Action<int>))]
private static string NameOfT<T>(T item)
{
return typeof(T).Name;
}
某些平台不支持使用线程,因此任何使用System.Threading命名空间在运行时失败。.NET 类库的某些部分还隐式依赖于线程。一个常见的例子是System.Timers.Timer类,这取决于对线程的支持。
IL2CPP 支持异常过滤器。但是,filter 语句和 catch 块的执行顺序不同,因为 IL2CPP 使用 C++ 异常来实现托管异常。除非筛选器块写入字段,否则这并不明显。
IL2CPP 不支持反射MarshalAs和FieldOffset运行时的属性。它在编译时确实支持这些属性。应使用这些来进行正确的平台调用封送处理。
IL2CPP 不支持 C#dynamic关键词。此关键字需要 JIT 编译,而 IL2CPP 无法实现这一点。
IL2CPP 不支持Marshal.Prelink或Marshal.PrelinkAllAPI 方法。
IL2CPP 不支持System.Diagnostics.ProcessAPI 方法。对于在桌面平台上需要这样做的情况,请使用 Mono 脚本后端。