Version: 2020.1
通用函数
脚本序列化

脚本限制

Unity strives to provide a common scripting API and experience across all platforms it supports. However, some platforms have inherent restrictions. To help you understand these restrictions and support cross-platform code, the following table describes which restrictions apply to each platform and scripting backend:

.NET 4.x 等效脚本运行时

平台(脚本后端) 提前编译 无线程 .NET Core 类库子集
Android (IL2CPP)
Android (Mono)
iOS (IL2CPP)
PlayStation 4 (IL2CPP)
PlayStation Vita (IL2CPP)
独立平台 (IL2CPP)
独立平台 (Mono)
Switch (IL2CPP)
通用 Windows 平台 (IL2CPP)
通用 Windows 平台 (.NET)
WebGL (IL2CPP)
WiiU (Mono)
XBox One (IL2CPP)

提前编译

Some platforms do not allow runtime code generation. Therefore, any managed code which depends upon just-in-time (JIT) compilation on the target device will fail. Instead, you need to compile all of the managed code ahead-of-time (AOT). Often, this distinction doesn’t matter, but in a few specific cases, AOT platforms require additional consideration.

System.Reflection.Emit

An AOT platform cannot implement any of the methods in the System.Reflection.Emit namespace. The rest of System.Reflection is acceptable, as long as the compiler can infer that the code used via reflection needs to exist at runtime.

序列化

AOT platforms can encounter issues with serialization and deserlization due to the use of reflection. If a type or method is only used via reflection as part of serialization or deserialization, the AOT compiler cannot detect that the code needs to be generated for the type or method.

通用虚拟方法

Generic methods require the compiler to do some additional work to expand the code written by the developer to the code executed on the device. For example, you need different code for List with an int or a double. In the presence of virtual methods, where behavior is determined at runtime rather than compile time, the compiler can easily require runtime code generation in places where it is not entirely obvious from the source code.

The following code example works exactly as expected on a JIT platform (it prints “Message value: Zero” to the console once):

using UnityEngine;
using System;

public class AOTProblemExample : MonoBehaviour, IReceiver
{
    public enum AnyEnum 
    {
        Zero,
        One,
    }

    void Start() 
    {
        // 微妙的触发器:管理器的类型*必须*是
        // IManager(而不是 Manager)才能触发 AOT 问题。
        IManager manager = new Manager();
        manager.SendMessage(this, AnyEnum.Zero);
    }

    public void OnMessage<T>(T value) 
    {
        Debug.LogFormat("Message value: {0}", value);
    }
}

public class Manager : IManager 
{
    public void SendMessage<T>(IReceiver target, T value) {
        target.OnMessage(value);
    }
}

public interface IReceiver
{
    void OnMessage<T>(T value);
}

public interface IManager 
{
    void SendMessage<T>(IReceiver target, T value);
}

However, when you execute this code on an AOT platform with the IL2CPP scripting backend, this exception occurs:

ExecutionEngineException: Attempting to call method 'AOTProblemExample::OnMessage<AOTProblemExample+AnyEnum>' for which no ahead of time (AOT) code was generated.
  at Manager.SendMessage[T] (IReceiver target, .T value) [0x00000] in <filename unknown>:0 
  at AOTProblemExample.Start () [0x00000] in <filename unknown>:0

同样,Mono 脚本后端提供以下类似的异常:

  ExecutionEngineException: Attempting to JIT compile method 'Manager:SendMessage<AOTProblemExample/AnyEnum> (IReceiver,AOTProblemExample/AnyEnum)' while running with --aot-only.
    at AOTProblemExample.Start () [0x00000] in <filename unknown>:0

The AOT compiler does not realize that it should generate code for the generic method OnMessage with a T of AnyEnum, so it continues, skipping this method. When that method is called, and the runtime can’t find the proper code to execute, it returns this error message.

To work around an AOT issue like this, you can force the compiler to generate the proper code. You can add the following example method to the AOTProblemExample class:

public void UsedOnlyForAOTCodeGeneration() 
{
    // IL2CPP 只需要这一行。
    OnMessage(AnyEnum.Zero);

    //Mono 也需要这一行。请注意,我们
    // 直接在 Manager 而不是 IManager 接口上调用。
    new Manager().SendMessage(null, AnyEnum.Zero);

    //包含一个异常,这样我们就可以确定是否调用过该方法。
    throw new InvalidOperationException("This method is used for AOT code generation only.Do not call it at runtime.");
}

When the compiler encounters the explicit call to OnMessage with a T of AnyEnum, it generates the proper code for the runtime to execute. The method UsedOnlyForAOTCodeGeneration does not need to be called; it just needs to exist for the compiler to see it.

Calling managed methods from native code

Managed methods that need to be marshaled to a C function pointer so that they can be called from native code have a few restructions on AOT platforms:

  • The managed method must be a static method
  • The managed method must have the [MonoPInvokeCallback] attribute

无线程

Some platforms do not support the use of threads, so any managed code that uses the System.Threading namespace will fail at runtime. Also, some parts of the .NET class libraries implicitly depend upon threads. An often-used example is the System.Timers.Timer class, which depends on support for threads.

Exception filters

IL2CPP does not support C# exception filters. You should modify the code that depends on exception filters into the proper catch blocks.

TypedReference

IL2CPP does not support the System.TypedReference type or the __makeref C# keyword.


  • 删除了三星电视支持。
  • 在 Unity 2018.3 中已弃用 .Net 3.5 脚本运行时 NewIn20183
通用函数
脚本序列化