Share via


Migrar la aplicación de Windows 8.x a .NET Native

.NET Native proporciona una compilación estática de aplicaciones en Microsoft Store o en el equipo del desarrollador. Esto difiere de la compilación dinámica realizada para las aplicaciones de Windows 8.x (también denominadas anteriormente aplicaciones de Microsoft Store) por el compilador Just-In-Time (JIT) o el Generador de imágenes nativas (Ngen.exe) en el dispositivo. A pesar de las diferencias, .NET Native intenta mantener la compatibilidad con .NET para aplicaciones de Windows 8.x. Por lo general, las cosas que funcionan en las aplicaciones de .NET para Windows 8.x también funcionan con .NET Native. Sin embargo, en algunos casos, puede encontrar cambios de comportamiento. En este documento se describen estas diferencias entre las aplicaciones estándar de .NET para Windows 8.x y las .NET Native en las siguientes áreas:

Diferencias de tiempo de ejecución generales

  • Las excepciones, como TypeLoadException, producidas por el compilador JIT cuando una aplicación se ejecuta en Common Language Runtime (CLR) suelen producir errores en tiempo de compilación cuando se procesan por .NET Native.

  • No llame al método GC.WaitForPendingFinalizers desde un subproceso de interfaz de usuario de una aplicación. Esto puede dar lugar a un interbloqueo en .NET Native.

  • No confíe en el orden de invocación de constructores de clases estáticas. En .NET Native, el orden de invocación es diferente del orden en tiempo de ejecución estándar. (Incluso con el tiempo de ejecución estándar, no debe confiar en el orden de ejecución de los constructores de clases estáticas).

  • Un bucle infinito sin hacer una llamada (por ejemplo, while(true);) en cualquier subproceso puede hacer que la aplicación se detenga. De igual modo, las esperas largas o infinitas pueden detener la aplicación.

  • Ciertos ciclos de inicialización genéricos no inician excepciones en .NET Native. Por ejemplo, el código siguiente produce una excepción TypeLoadException en el CLR estándar. En .NET Native, no.

    using System;
    
    struct N<T> {}
    struct X { N<X> x; }
    
    public class Example
    {
       public static void Main()
       {
          N<int> n = new N<int>();
          X x = new X();
       }
    }
    
  • En algunos casos, .NET Native proporciona diferentes implementaciones de bibliotecas de clases de .NET Framework. Un objeto devuelto desde un método siempre implementará los miembros del tipo devuelto. Sin embargo, dado que su implementación de respaldo es diferente, es posible que no pueda convertirlo en el mismo conjunto de tipos como lo haría en otras plataformas de .NET Framework. Por ejemplo, en algunos casos, es posible que no pueda convertir el objeto de interfaz IEnumerable<T> devuelto por métodos como TypeInfo.DeclaredMembers o TypeInfo.DeclaredProperties a T[].

  • La memoria caché de WinInet no está habilitada de forma predeterminada en las aplicaciones de .NET para Windows 8.x, pero está en .NET Native. Esto mejora el rendimiento, pero tiene implicaciones en el conjunto de trabajo. No es necesaria ninguna acción por parte del desarrollador.

Diferencias de programación dinámicas

.NET Native vínculos estáticos en el código de .NET Framework para que el código sea local para obtener el máximo rendimiento. Sin embargo, el tamaño de los archivos binarios debe seguir siendo reducido para dar cabida a la totalidad de .NET Framework. El compilador de .NET Native resuelve esta limitación mediante un reductor de dependencias que quita las referencias al código no usado. Sin embargo, es posible que .NET Native no mantengan o generen información de tipo y código cuando esa información no se pueda deducir estáticamente en tiempo de compilación, sino que se recupera dinámicamente en tiempo de ejecución.

.NET Native habilita la reflexión y la programación dinámica. Sin embargo, no todos los tipos se pueden marcar para la reflexión, ya que esto haría que el tamaño de código generado sea demasiado grande (especialmente porque se admite la reflexión en las API públicas en .NET Framework). El compilador de .NET Native toma decisiones inteligentes sobre qué tipos deben admitir la reflexión y mantiene los metadatos y genera código solo para esos tipos.

Por ejemplo, el enlace de datos requiere una aplicación para poder asignar los nombres de propiedad a las funciones. En las aplicaciones de .NET para Windows 8.x, Common Language Runtime usa automáticamente la reflexión para proporcionar esta funcionalidad para los tipos administrados y los tipos nativos disponibles públicamente. En .NET Native, el compilador incluye automáticamente metadatos para los tipos a los que enlaza datos.

El compilador de .NET Native también puede controlar tipos genéricos usados habitualmente como List<T> y Dictionary<TKey,TValue>, que funcionan sin necesidad de ninguna sugerencia o directiva. La palabra clave dynamic también se admite dentro de ciertos límites.

Nota

Debe probar todas las rutas de acceso de código dinámicas exhaustivamente al migrar la aplicación a .NET Native.

La configuración predeterminada para .NET Native es suficiente para la mayoría de los desarrolladores, pero es posible que algunos desarrolladores quieran ajustar sus configuraciones mediante un archivo de directivas en tiempo de ejecución (.rd.xml). Además, en algunos casos, el compilador de .NET Native no puede determinar qué metadatos deben estar disponibles para la reflexión y se basan en sugerencias, especialmente en los casos siguientes:

  • Algunas construcciones como Type.MakeGenericType y MethodInfo.MakeGenericMethod no se pueden determinar estáticamente.

  • Dado que el compilador no puede determinar la creación de instancias, un tipo genérico que desee reflejar tiene que especificarse mediante directivas de tiempo de ejecución. Esto no es solo porque se debe incluir todo el código, sino también porque la reflexión en tipos genéricos puede formar un ciclo infinito (por ejemplo, cuando se invoca un método genérico en un tipo genérico).

Nota

Las directivas de tiempo de ejecución se definen en un archivo de directivas de tiempo de ejecución (.rd.xml). Para obtener información general sobre el uso de este archivo, vea Getting Started (Introducción). Para obtener información sobre las directivas de tiempo de ejecución, vea Runtime Directives (rd.xml) Configuration File Reference.

.NET Native también incluye herramientas de generación de perfiles que ayudan al desarrollador a determinar qué tipos fuera del conjunto predeterminado deben admitir la reflexión.

Hay varias diferencias individuales relacionadas con la reflexión en el comportamiento entre las aplicaciones de .NET para Windows 8.x y .NET Native.

En .NET Native:

  • No se admite la reflexión privada sobre los tipos y miembros de la biblioteca de clases de .NET Framework. Sin embargo, puede reflejar sobre sus propios tipos y miembros privados, así como sobre los tipos y miembros de bibliotecas de terceros.

  • La propiedad ParameterInfo.HasDefaultValue devuelve correctamente false para un objeto ParameterInfo que representa un valor devuelto. En .NET para aplicaciones de Windows 8.x, devuelve true. El lenguaje intermedio (IL) no admite esto directamente y la interpretación se deja en el idioma.

  • Los miembros públicos de las estructuras RuntimeFieldHandle y RuntimeMethodHandle no son compatibles. Estos tipos solo son compatibles con LINQ, árboles de expresión e inicialización de matrices estáticas.

  • RuntimeReflectionExtensions.GetRuntimeProperties y RuntimeReflectionExtensions.GetRuntimeEvents incluyen miembros ocultos en clases base y, por tanto, se pueden invalidar sin necesidad de hacerlo de forma explícita. Esto también es así para otros métodos RuntimeReflectionExtensions.GetRuntime* .

  • Type.MakeArrayType y Type.MakeByRefType no se produce un error al intentar crear determinadas combinaciones (por ejemplo, una matriz de byref objetos).

  • No se puede utilizar la reflexión para invocar a los miembros que tienen parámetros de puntero.

  • No se puede utilizar la reflexión para obtener o establecer un campo de puntero.

  • Cuando el recuento de argumentos es incorrecto y el tipo de uno de los argumentos es incorrecto, .NET Native inicia una ArgumentException excepción en lugar de .TargetParameterCountException

  • Por lo general, no se admite la serialización binaria de excepciones. Como resultado, se pueden agregar objetos no serializables al diccionario Exception.Data .

Escenarios no compatibles e interfaces API

En las secciones siguientes se enumeran varios escenarios e interfaces API no compatibles con el desarrollo general, la interoperabilidad y las tecnologías como HTTPClient y Windows Communication Foundation (WCF):

Diferencias de desarrollo generales

Tipos de valor

  • Si invalida los métodos ValueType.Equals y ValueType.GetHashCode para un tipo de valor, no llame a las implementaciones de la clase base. En las aplicaciones de .NET para Windows 8.x, estos métodos se basan en la reflexión. En tiempo de compilación, .NET Native genera una implementación que no se basa en la reflexión en tiempo de ejecución. Esto significa que si no invalida estos dos métodos, funcionarán según lo previsto, ya que .NET Native genera la implementación en tiempo de compilación. Sin embargo, si se invalidan estos métodos, pero se llama a la implementación de la clase base, se produce una excepción.

  • No se admiten tipos de valor mayores de 1 megabyte.

  • Los tipos de valor no pueden tener un constructor sin parámetros en .NET Native. (C# y Visual Basic prohíben constructores sin parámetros en tipos de valor. Sin embargo, estos se pueden crear en IL).

Matrices

  • No se admiten matrices con límite inferior distinto de cero. Normalmente, estas matrices se crean mediante una llamada a la sobrecarga Array.CreateInstance(Type, Int32[], Int32[]) .

  • No se admite la creación dinámica de matrices multidimensionales. Estas matrices se crean normalmente mediante una llamada a una sobrecarga del método Array.CreateInstance que incluye un parámetro lengths , o mediante una llamada al método Type.MakeArrayType(Int32) .

  • No se admiten matrices multidimensionales que tengan cuatro o más dimensiones; es decir, que el valor de su propiedad Array.Rank sea de cuatro o más. En su lugar, use matrices escalonadas (una matriz de matrices). Por ejemplo, array[x,y,z] no es válido, pero array[x][y][z] sí lo es.

  • No se admite varianza en matrices multidimensionales, ya que causa una excepción InvalidCastException en tiempo de ejecución.

Genéricos

  • La expansión infinita de tipos genéricos produce un error del compilador. Por ejemplo, este código produce un error al compilar:

    class A<T> {}
    
    class B<T> : A<B<A<T>>>
    {}
    

Punteros

  • No se admiten las matrices de punteros.

  • No se puede utilizar la reflexión para obtener o establecer un campo de puntero.

Serialización

No se admite el atributo KnownTypeAttribute(String) . En su lugar, use el atributo KnownTypeAttribute(Type) .

Recursos

No se admite el uso de recursos localizados con la clase EventSource . La propiedad EventSourceAttribute.LocalizationResources no define los recursos localizados.

Delegados

No se admiteDelegate.BeginInvoke ni Delegate.EndInvoke .

Otras API

  • La propiedad TypeInfo.GUID produce una PlatformNotSupportedException excepción si un GuidAttribute atributo no se aplica al tipo. El GUID se utiliza principalmente para la compatibilidad con COM.

  • El DateTime.Parse método analiza correctamente las cadenas que contienen fechas cortas en .NET Native. Sin embargo, no mantiene la compatibilidad con ciertos cambios en el análisis de fecha y hora.

  • BigInteger.ToString("E")se redondea correctamente en .NET Native. En algunas versiones de CLR, la cadena resultante se trunca en lugar de redondearse.

Diferencias de HttpClient

En .NET Native, la HttpClientHandler clase usa internamente WinINet (a través de la HttpBaseProtocolFilter clase ) en lugar de las WebRequest clases y WebResponse usadas en las aplicaciones estándar de .NET para Windows 8.x. WinINet no admite todas las opciones de configuración que admite la clase HttpClientHandler . Como resultado:

  • Algunas de las propiedades de funcionalidad que HttpClientHandler se devuelven false en .NET Native, mientras que se devuelven true en las aplicaciones estándar de .NET para Windows 8.x.

  • Algunos de los descriptores de acceso de propiedad get de configuración siempre devuelven un valor fijo en .NET Native que es diferente del valor configurable predeterminado en las aplicaciones de .NET para Windows 8.x.

En las subsecciones siguientes se tratan algunas otras diferencias de comportamiento.

Proxy

La HttpBaseProtocolFilter clase no admite la configuración ni invalidación del proxy por solicitud. Esto significa que todas las solicitudes de .NET Native usan el servidor proxy configurado por el sistema o ningún servidor proxy, según el valor de la HttpClientHandler.UseProxy propiedad. En las aplicaciones de .NET para Windows 8.x, el servidor proxy se define mediante la HttpClientHandler.Proxy propiedad . En .NET Native, al establecer en HttpClientHandler.Proxy un valor distinto null de se produce una PlatformNotSupportedException excepción. La HttpClientHandler.SupportsProxy propiedad devuelve false en .NET Native, mientras que devuelve true en las aplicaciones estándar de .NET Framework para Windows 8.x.

Redireccionamiento automático

La HttpBaseProtocolFilter clase no permite configurar el número máximo de redirecciones automáticas. El valor de la HttpClientHandler.MaxAutomaticRedirections propiedad es 50 de forma predeterminada en las aplicaciones estándar de .NET para Windows 8.x y se puede modificar. En .NET Native, el valor de esta propiedad es 10 y al intentar modificarla se produce una PlatformNotSupportedException excepción. La HttpClientHandler.SupportsRedirectConfiguration propiedad devuelve false en .NET Native, mientras que devuelve true en .NET para aplicaciones de Windows 8.x.

Descompresión automática

.NET para aplicaciones de Windows 8.x permite establecer la propiedad en , GZip, y DeflateGZip, o None.DeflateHttpClientHandler.AutomaticDecompression .NET Native solo admite Deflate junto con GZip, o None. Si se intenta establecer la propiedad AutomaticDecompression en Deflate o GZip , la propiedad se establece, de forma silenciosa, en Deflate y GZip.

Cookies

La administración de cookies se realiza simultáneamente mediante HttpClient y WinINet. Las cookies de CookieContainer se combinan con las cookies de la caché de cookies de WinINet. Si se elimina una cookie de CookieContainer , se evita que HttpClient envíe la cookie, pero si WinINet ya ha visto la cookie y el usuario no ha eliminado las cookies, WinINet la envía. No es posible eliminar una cookie de WinINet mediante programación con las API HttpClient, HttpClientHandlero CookieContainer . Si se establece la propiedad HttpClientHandler.UseCookies en false , solo se consigue que HttpClient deje de enviar cookies; puede que WinINet siga incluyendo sus cookies en la solicitud.

Credenciales

En las aplicaciones de .NET para Windows 8.x, las HttpClientHandler.UseDefaultCredentials propiedades y HttpClientHandler.Credentials funcionan de forma independiente. Además, la propiedad Credentials acepta cualquier objeto que implemente la interfaz ICredentials . En .NET Native, establecer la UseDefaultCredentials propiedad en true hace que la Credentials propiedad se convierta en null. Además, la propiedad Credentials solo se puede establecer en null, DefaultCredentialso en un objeto de tipo NetworkCredential. Si se asigna cualquier otro objeto ICredentials (el más conocido es CredentialCache) a la propiedad Credentials , se produce una excepción PlatformNotSupportedException.

Otras características no compatibles o no configurables

En .NET Native:

Diferencias de interoperabilidad

Interfaces API desusadas

Hay una serie de interfaces API poco utilizadas para la interoperabilidad con código administrado que están desusadas. Cuando se usa con .NET Native, estas API pueden producir una NotImplementedException excepción o PlatformNotSupportedException , o provocar un error del compilador. En las aplicaciones de .NET para Windows 8.x, estas API se marcan como obsoletas, aunque llamarlas generan una advertencia del compilador en lugar de un error del compilador.

Las API en desuso para VARIANT serializar incluyen:

UnmanagedType.Struct se admite, pero produce una excepción en algunos escenarios, como cuando se usa con IDispatch o byref variantes.

Las API en desuso para la compatibilidad con IDispatch incluyen:

Las API en desuso para eventos COM clásicos incluyen:

Las API en desuso en la System.Runtime.InteropServices.ICustomQueryInterface interfaz, que no se admiten en .NET Native, incluyen:

Otras características de interoperabilidad no admitidas incluyen:

API de serialización poco usadas:

Compatibilidad con la invocación de plataforma y la interoperabilidad COM

La mayoría de los escenarios de invocación de plataforma e interoperabilidad COM siguen siendo compatibles con .NET Native. En particular, se admite toda la interoperabilidad con las API de Windows en tiempo de ejecución (WinRT) y todo el cálculo de referencias necesarias para Windows en tiempo de ejecución. Esto incluye compatibilidad de cálculo de referencias para:

Sin embargo, .NET Native no admite lo siguiente:

No se admite el uso de la reflexión para invocar un método de invocación de plataforma. Puede evitar esta limitación si encapsula la llamada de método en otro método y utiliza la reflexión para llamar en su lugar al contenedor.

Otras diferencias de las API de .NET para aplicaciones de Windows 8.x

En esta sección se enumeran las API restantes que no se admiten en .NET Native. El conjunto más grande de las API no admitidas es las API de Windows Communication Foundation (WCF).

DataAnnotations (System.ComponentModel.DataAnnotations)

Los tipos de los System.ComponentModel.DataAnnotations espacios de nombres y System.ComponentModel.DataAnnotations.Schema no se admiten en .NET Native. Estos incluyen los siguientes tipos que están presentes en las aplicaciones de .NET para Windows 8.x:

Visual Basic

Visual Basic no se admite actualmente en .NET Native. Los siguientes tipos en los Microsoft.VisualBasic espacios de nombres y Microsoft.VisualBasic.CompilerServices no están disponibles en .NET Native:

Contexto de reflexión (espacio de nombres System.Reflection.Context)

La System.Reflection.Context.CustomReflectionContext clase no se admite en .NET Native.

RTC (System.Net.Http.Rtc)

La System.Net.Http.RtcRequestFactory clase no se admite en .NET Native.

Windows Communication Foundation (WCF) (System.ServiceModel.*)

Los tipos de los espacios de nombres System.ServiceModel.* no se admiten en .NET Native. Estos incluyen los siguientes tipos:

Diferencias en los serializadores

Las siguientes diferencias conciernen a la serialización y deserialización con las clases DataContractSerializer, DataContractJsonSerializery XmlSerializer :

Diferencias de Visual Studio

Excepciones y depuración

Cuando se ejecutan aplicaciones compiladas mediante .NET Native en el depurador, se habilitan las excepciones de primera oportunidad para los siguientes tipos de excepciones:

Creación de aplicaciones

Use las herramientas de compilación x86 que se utilizan de manera predeterminada en Visual Studio. No recomendamos el uso de las herramientas de MSBuild AMD64, ya que podrían crear problemas de compilación. Estas herramientas se encuentran en C:\Archivos de programa (x86)\MSBuild\12.0\bin\amd64.

Generadores de perfiles

  • El generador de perfiles de CPU de Visual Studio CPU y el generador de perfiles de memoria de XAML no muestran correctamente Just-My-Code (solo mi código).

  • El generador de perfiles de memoria de XAML no muestra con precisión los datos del montón administrado.

  • El generador de perfiles de CPU no identifica correctamente los módulos y muestra nombres de función prefijados.

Proyectos de biblioteca de prueba unitaria

No se admite la habilitación de .NET Native en una biblioteca de pruebas unitarias para un proyecto de aplicación de Windows 8.x y hace que el proyecto no se compile.

Vea también