Funciones genéricas
Serialización de Script

Restricciones de Scripting

Nosotros nos esforzamos para proporcionar un scripting API común y experiencia a través de todas las plataformas que Unity soporta. Sin embargo, algunas plataformas tienen restricciones inherentes. Para ayudarlo a entender estas restricciones y soporte de código multi-plataforma, la siguiente tabla describe qué restricciones aplican a cada plataforma y scripting backend:

Plataforma _Backend de Scripting Restricciones
Standalone Mono Ninguno
WebGL IL2CPP Complicación con anticipación, Sin hilos
iOS IL2CPP Compilación con anticipación
Android Mono Ninguno
Android IL2CPP Compilación con anticipación
Samsung TV Mono Compilación con anticipación
Tizen Mono Compilación con anticipación
XBox 360 Mono Compilación con anticipación
XBox One Mono Compilación con anticipación
XBox One IL2CPP Compilación con anticipación
WiiU Mono Compilación con anticipación
PS3 Mono Compilación con anticipación
PS Vita Mono Compilación con anticipación
PS Vita IL2CPP Compilación con anticipación
PS4 Mono Compilación con anticipación
PS4 IL2CPP Compilación con anticipación
Windows Store .NET Utiliza un subconjunto de las librerías de la clase .NET Core
Windows Store IL2CPP Compilación con anticipación

Complicación con anticipación

Algunas plataformas no permiten la generación de código en tiempo de ejecución. Por lo tanto, cualquier managed code que depende en una compilación justo a tiempo (JIT) en el dispositivo objetivo va a fallar. Más bien, nosotros necesitamos compilar todo el managed code con anticipación (AOT). A menudo, esta distinción no importa, pero en algunos casos específicos, las plataformas AOT requieren una consideración adicional.

System.Reflection.Emit

Una plataforma AOT no puede implementar cualquiera de los métodos en el namespace System.Reflection.Emit. Tenga en cuenta que el resto de System.Reflection es aceptable, mientras que el compilador puede inferir que el código utilizado vía el reflection necesita existir en tiempo de ejecución.

Serialización

Las plataformas AOT pueden encontrarse con problemas con la serialización y des-serialización debido al uso de reflection. Si un tipo o método es únicamente utilizado vía reflection como parte de la serialización o des-serialización, el compilador AOT no puede detectar que ese código necesita estar generado para el tipo o método.

Métodos virtuales genéricos

Los métodos genéricos requieren que compilador haga trabajo adicional para expandir el código escrito por el desarrollador al código que en realidad es ejecutado en el dispositivo. Por ejemplo, nosotros necesitamos un código diferente para List con un int o un double. En la presencia de métodos virtuales, dónde el comportamiento es determinado en tiempo de ejecución en vez de en el tiempo de compilación, el compilador puede fácilmente requerir la generación de código en tiempo de ejecución en lugares dónde no es completamente obvio dado por el código fuente.

Suponga que nosotros tenemos el siguiente código, el cual funciona exactamente como se espera en una plataforma JIT (este imprime el “Message value: Zero” (Valor del mensaje : cero) a la consola solo una vez):

using UnityEngine;
using System;

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

    void Start() {
        // Subtle trigger: The type of manager *must* be
        // IManager, not Manager, to trigger the AOT problem.
        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);
}

Cuando este código es ejecutado en la plataforma AOT con el backend de scripting IL2CPP, esta excepción ocurre:

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 

Del mismo modo, el backend de scripting Mono proporciona esta excepción similar:

  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 

El compilador AOT no se da cuenta que debería generar código para el método genérico OnMessage con una T de AnyEnum, por lo que felizmente sigue omitiendo este método. Cuando este método es llamado y el tiempo de ejecución no puede encontrar el código adecuado para ejecutar, cede con este mensaje de error.

Para solucionar un problema AOT así, nosotros a menudo obligamos al compilador en generar el código adecuado para nosotros. Si nosotros agregamos un método como este a la clase AOTProblemExample:

public void UsedOnlyForAOTCodeGeneration() {
    // IL2CPP needs only this line.
    OnMessage(AnyEnum.Zero);

    // Mono also needs this line. Note that we are
    // calling directly on the Manager, not the IManager interface.
    new Manager().SendMessage(null, AnyEnum.Zero);

    // 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.");
}

Cuando el compilador se encuentra con el llamado explícito a OnMessage con una T de AnyEnum, este genera el código adecuado para que en tiempo de ejecución se ejecute. El método ** UsedOnlyForAOTCodeGeneration** nunca necesita ser llamado; solamente tiene que existir para que el compilador lo vea.

** Sin hilos

Algunas plataformas no soportan el uso de hilos, por lo que cualquier managed code que utilice el namespace System.Threading va a fallar en tiempo de ejecución. También, algunas partes de las librerías de la clase .NET implícitamente dependen en hilos. Un ejemplo usado a menudo es la clase System.Timers.Timer, el cual depende en el soporte de hilos.

Funciones genéricas
Serialización de Script