Funciones genéricas
Script Serialization

Scripting restrictions

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:

.NET 4.x equivalent scripting runtime

Platform (scripting backend) Ahead-of-time compile No threads .NET Core class libraries subset
Android (IL2CPP)
Android (Mono)
iOS (IL2CPP)
PlayStation 4 (IL2CPP)
PlayStation Vita (IL2CPP)
Standalone (IL2CPP)
Standalone (Mono)
Switch (IL2CPP)
Universal Windows Platform (IL2CPP)
Universal Windows Platform (.NET)
WebGL (IL2CPP)
WiiU (Mono)
XBox One (IL2CPP)

.NET 3.5 equivalent scripting runtime

Platform (scripting backend) Ahead-of-time compile No threads .NET Core class libraries subset
Android (IL2CPP)
Android (Mono)
iOS (IL2CPP)
PlayStation 4 (IL2CPP)
PlayStation 4 (Mono)
PlayStation Vita (IL2CPP)
PlayStation Vita (Mono)
Standalone (IL2CPP)
Standalone (Mono)
Switch (IL2CPP)
Universal Windows Platform (IL2CPP)
Universal Windows Platform (.NET)
WebGL (IL2CPP)
WiiU (Mono)
XBox One (IL2CPP)
XBox One (Mono)

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.


  • 2017–11–20 Page amended with no editorial review

  • Se quita el soporte a Samsung TV

Funciones genéricas
Script Serialization