Migrazione dell'app di Windows 8.x a .NET Native

.NET Native fornisce la compilazione statica delle app in Microsoft Store o nel computer dello sviluppatore. Ciò differisce dalla compilazione dinamica eseguita per le app di Windows 8.x (in precedenza chiamate app di Microsoft Store) dal compilatore JIT (Just-In-Time) o dal generatore di immagini native (Ngen.exe) nel dispositivo. Nonostante le differenze, .NET Native tenta di mantenere la compatibilità con .NET per le app di Windows 8.x. Per la maggior parte, ciò che funziona su .NET per le app di Windows 8.x funziona anche con .NET Native. Tuttavia, in alcuni casi, è possibile riscontrare differenze di comportamento. Questo documento illustra queste differenze tra le app .NET standard per Windows 8.x e .NET Native nelle seguenti aree:

Differenze generali di runtime

  • Eccezioni, ad esempio TypeLoadException, che vengono generate dal compilatore JIT quando un'app viene eseguita su Common Language Runtime (CLR), in genere produce errori in fase di compilazione quando vengono elaborate da .NET Native.

  • Non chiamare il metodo GC.WaitForPendingFinalizers da un thread UI dell'app. Ciò può causare un deadlock in .NET Native.

  • Non fare affidamento sull'ordine di chiamata del costruttore di classe statica. In .NET Native, l'ordine di chiamata è diverso dall'ordine in fase di esecuzione standard. (anche con il runtime standard, non è consigliabile fare affidamento sull'ordine di esecuzione dei costruttori di classe statici).

  • Un ciclo infinito senza eseguire una chiamata (ad esempio, while(true);) su qualsiasi thread può comportare l'arresto dell'applicazione. Allo stesso modo, attese lunghe o infinite possono portare all'arresto dell'applicazione.

  • Alcuni cicli di inizializzazione generici non generano eccezioni in .NET Native. Ad esempio, il codice seguente genera un'eccezione TypeLoadException sul CLR standard, In .NET Native non lo fa.

    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();
       }
    }
    
  • In alcuni casi, .NET Native fornisce implementazioni diverse delle librerie di classi .NET Framework. Un oggetto restituito da un metodo implementerà sempre i membri del tipo restituito. Tuttavia, poiché l'implementazione di supporto è diversa, potrebbe non essere possibile eseguire il cast per la stessa raccolta di tipi come su altre piattaforme di.NET Framework. Ad esempio, in alcuni casi, potrebbe non essere possibile eseguire il cast dell'oggetto di interfaccia IEnumerable<T> restituito da metodi quali TypeInfo.DeclaredMembers o TypeInfo.DeclaredProperties a T[].

  • La cache WinInet non è abilitata per impostazione predefinita in .NET per le app di Windows 8.x, ma è in .NET Native. Questo migliora le prestazioni, ma ha implicazioni sul working set. Non è necessaria alcuna azione da parte dello sviluppatore.

Differenze di programmazione dinamica

.NET Native collega in modo statico il codice da .NET Framework per rendere il codice dell'app e ottenere prestazioni ottimali. Tuttavia, le dimensioni binarie devono rimanere ridotte, in modo da non consentire il passaggio dell'intero.NET Framework. Il compilatore di .NET Native risolve questa limitazione usando un riduttore di dipendenza che rimuove i riferimenti al codice inutilizzato. Tuttavia, .NET Native potrebbe non gestire o generare alcune informazioni sul tipo e il codice quando tali informazioni non possono essere dedotte in modo statico in fase di compilazione, ma al contrario vengono recuperate in modo dinamico in fase di esecuzione.

.NET Native abilita la reflection e la programmazione dinamica. Tuttavia, non tutti i tipi possono essere contrassegnati per la reflection, perché ciò renderebbe eccessive le dimensioni del codice generato (soprattutto perché la reflection sulle API pubbliche in .NET Framework è supportata). Il compilatore di .NET Native opera scelte intelligenti sui tipi che devono supportare la reflection e mantiene i metadati generando il codice solo per tali tipi.

Ad esempio, il data binding richiede che un'applicazione possa eseguire il mapping dei nomi di proprietà alle funzioni. In .NET per applicazioni Windows 8.x, Common Language Runtime usa automaticamente la reflection per fornire questa funzionalità per i tipi gestiti e i tipi nativi disponibili pubblicamente. In .NET Native, il compilatore include automaticamente i metadati per i tipi a cui si associano i dati.

Il compilatore .NET Native può anche gestire tipi generici di uso comune, come List<T> e Dictionary<TKey,TValue>, che funzionano senza richiedere hint o direttive. È supportata anche la parola chiave dinamica entro certi limiti.

Nota

È consigliabile testare accuratamente tutti i percorsi di codice dinamico durante la conversione dell'app in .NET Native.

La configurazione predefinita per .NET Native è sufficiente per la maggior parte degli sviluppatori, ma per alcuni sviluppatori potrebbero voler ottimizzare le configurazioni usando un file di direttive di runtime (.rd.xml). Inoltre, in alcuni casi, il compilatore .NET Native non può determinare quali metadati devono essere disponibili per la reflection e si basa su hint, in particolare nei casi seguenti:

  • Alcuni costrutti come Type.MakeGenericType e MethodInfo.MakeGenericMethod non possono essere determinati staticamente.

  • Poiché il compilatore non può determinare le istanze create, un tipo generico di cui si vuole effettuare la reflection deve essere specificato dalle direttive di runtime. Ciò non solo perché è necessario includere tutto il codice, ma anche perché la reflection sui tipi può creare un ciclo infinito (ad esempio, quando un metodo generico viene richiamato su un tipo generico).

Nota

Le direttive di runtime sono definite in un file nelle direttive di runtime (rd.xml). Per informazioni generali sull'uso di questo file, vedere Introduzione. Per informazioni sulle direttive di runtime, vedere Runtime Directives (rd.xml) Configuration File Reference.

.NET Native include anche strumenti di profilatura che consentono allo sviluppatore di determinare quali tipi al di fuori del set predefinito devono supportare la reflection.

Esistono diverse altre differenze di comportamento correlate alla reflection tra .NET per le app di Windows 8.x e .NET Native.

In .NET Native:

  • La reflection privata su tipi e membri della libreria di classi .NET Framework non è supportata. È tuttavia possibile riflettere sui propri tipi e membri privati, nonché sui tipi e membri nelle librerie di terze parti.

  • La proprietà ParameterInfo.HasDefaultValue restituisce correttamente false per un oggetto ParameterInfo che rappresenta un valore restituito. In .NET per le app di Windows 8.x restituisce true. Il linguaggio intermedio (IL) non supporta direttamente questa situazione e l'interpretazione viene lasciata alla lingua.

  • I membri pubblici sulle strutture RuntimeFieldHandle e RuntimeMethodHandle non sono supportati. Questi tipi sono supportati solo per LINQ, gli alberi delle espressioni e l'inizializzazione di matrice statica.

  • RuntimeReflectionExtensions.GetRuntimeProperties e RuntimeReflectionExtensions.GetRuntimeEvents includono membri nascosi in classi di base e perciò potrebbero essere sottoposti a override esplicito. Ciò vale anche per gli altri metodi RuntimeReflectionExtensions.GetRuntime* .

  • Type.MakeArrayType e Type.MakeByRefType e non hanno esito negativo quando si prova a creare determinate combinazioni (ad esempio, una matrice di byref oggetti).

  • Non è possibile usare la reflection per richiamare i membri con parametri di puntatore.

  • Non è possibile usare la reflection per ottenere o impostare un campo del puntatore.

  • Quando il conteggio degli argomenti non è corretto e il tipo di uno degli argomenti non è corretto, .NET Native genera un'eccezione ArgumentException anziché TargetParameterCountException.

  • In genere la serializzazione binaria delle eccezioni non è supportata. Di conseguenza, è possibile aggiungere gli oggetti non serializzabili al dizionario Exception.Data .

Scenari e API non supportati

Nelle sezioni seguenti vengono elencati gli scenari e le API non supportati per lo sviluppo generale, l'interoperabilità e le tecnologie, ad esempio HTTPClient e Windows Communication Foundation (WCF):

Differenze generali per lo sviluppo

Tipi valore

  • Se si esegue l'override dei metodi ValueType.Equals e ValueType.GetHashCode per un tipo di valore, non chiamare le implementazioni della classe di base. In .NET per le app di Windows 8.x, questi metodi si basano sulla reflection. In fase di compilazione, .NET Native genera un'implementazione che non si basa sulla reflection di runtime. Ciò significa che se questi due metodi non vengono sottoposti a override, funzioneranno come previsto, perché .NET Native genera l'implementazione in fase di compilazione. Tuttavia, se si esegue l'override di questi metodi, ma si chiama l'implementazione della classe base verrà generata un'eccezione.

  • I tipi di valore maggiori di 1 megabyte non sono supportati.

  • I tipi valore non possono avere un costruttore senza parametri in .NET Native. (C# e Visual Basic impediscono costruttori senza parametri nei tipi valore. Tuttavia, questi possono essere creati in IL.)

Matrici

  • Non sono supportate le matrici con limite inferiore diverso da zero. Solitamente, queste matrici vengono create chiamando l'overload di Array.CreateInstance(Type, Int32[], Int32[]) .

  • Non è supportata la creazione dinamica di matrici multidimensionali. Tali matrici vengono in genere creata dalla chiamata di un overload del metodo Array.CreateInstance che include un parametro lengths oppure dalla chiamata del metodo Type.MakeArrayType(Int32) .

  • Le matrici multidimensionali con quattro o più dimensioni non sono supportate; vale a dire il relativo valore della proprietà Array.Rank è 4 o superiore. Usare invece le matrici irregolari (una matrice di matrici). Ad esempio, array[x,y,z] non è valido, mentre array[x][y][z] è valido.

  • La varianza per le matrici multidimensionali non è supportata e causa un'eccezione InvalidCastException in fase di esecuzione.

Generics

  • L'espansione di tipo generico infinito genera un errore del compilatore. Ad esempio, questo codice non viene compilato:

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

Puntatori

  • Le matrici di puntatori non sono supportate.

  • Non è possibile usare la reflection per ottenere o impostare un campo del puntatore.

Serializzazione

L'attributo KnownTypeAttribute(String) non è supportato. Usare piuttosto l'attributo KnownTypeAttribute(Type) .

Risorse

L'uso di risorse localizzate con la classe EventSource non è supportato. La proprietà EventSourceAttribute.LocalizationResources non definisce le risorse localizzate.

Delegati

Delegate.BeginInvoke e Delegate.EndInvoke non sono supportati.

Varie API

  • La proprietà TypeInfo.GUID genera un'eccezione PlatformNotSupportedException se un GuidAttribute attributo non viene applicato al tipo. Il GUID viene usato principalmente per il supporto COM.

  • Il metodo DateTime.Parse analizza correttamente le stringhe che contengono date brevi in .NET Native. Tuttavia, non mantiene la compatibilità con determinate modifiche nell'analisi di data e ora.

  • BigInteger.ToString("E") viene arrotondato correttamente in .NET Native. In alcune versioni di CLR, la stringa di risultato viene troncata anziché arrotondata.

Differenze di HttpClient

In .NET Native, la HttpClientHandler classe usa internamente WinINet (tramite la classe HttpBaseProtocolFilter ) anziché le classi WebRequest e WebResponse usate nelle app .NET standard per le app di Windows 8.x. WinINet non supporta tutte le opzioni di configurazione supportate dalla classe HttpClientHandler . Di conseguenza:

  • Alcune delle proprietà di funzionalità HttpClientHandler restituiscono false su .NET Native, mentre restituiscono true nelle app standard .NET per Windows 8.x.

  • Alcune funzioni di accesso alle proprietà get di configurazione restituiscono sempre un valore fisso in .NET Native diverso dal valore configurabile predefinito in .NET per le app di Windows 8.x.

Nelle sottosezioni riportate di seguito sono descritte alcune differenze di comportamento aggiuntive.

Proxy

La HttpBaseProtocolFilter classe non supporta la configurazione o l'override del proxy per ogni richiesta. Ciò significa che tutte le richieste su .NET Native usano il server proxy configurato dal sistema o nessun server proxy, a seconda del valore della HttpClientHandler.UseProxy proprietà. In .NET per le app di Windows 8.x il server proxy viene definito dalla HttpClientHandler.Proxy proprietà. In .NET Native, l'impostazione su HttpClientHandler.Proxy di un valore diverso da null genera un'eccezione PlatformNotSupportedException. La proprietà HttpClientHandler.SupportsProxy restituisce false in .NET Native, mentre restituisce true in .NET Framework standard per le app di Windows 8.x.

Reindirizzamento automatico

La classe HttpBaseProtocolFilter non consente la configurazione del numero massimo di reindirizzamenti automatici. Il valore della proprietà HttpClientHandler.MaxAutomaticRedirections è 50 per impostazione predefinita in .NET per le app di Windows 8.x standard e può essere modificato. In .NET Native, il valore di questa proprietà è 10 e il tentativo di modificarlo genera un'eccezione PlatformNotSupportedException. La proprietà HttpClientHandler.SupportsRedirectConfiguration restituisce false in .NET Native, mentre restituisce true in .NET per le app di Windows 8.x.

Decompressione automatica

.NET per le app di Windows 8.x consente di impostare HttpClientHandler.AutomaticDecompression la proprietà su Deflate, GZip, sia Deflate che GZipo None. .NET Native supporta solo Deflate insieme a GZip, o None. Provare a impostare la proprietà AutomaticDecompression su Deflate o GZip da soli comporta l'impostazione automatica su Deflate e GZip.

Cookies

La gestione dei cookie viene eseguita simultaneamente da HttpClient e WinINet. I cookie di CookieContainer vengono combinati con i cookie nella cache dei cookie di WinINet. La rimozione di un cookie da CookieContainer impedisce a HttpClient di inviarlo, ma se è già stato rilevato da WinINet, e i cookie non sono stati eliminati dall'utente, WinINet lo invia. Non è possibile rimuovere a livello di codice un cookie da WinINet usando le API HttpClient, HttpClientHandlero CookieContainer . L'impostazione della proprietà HttpClientHandler.UseCookies su false fa solo sì che HttpClient smetta di inviare cookie; WinINet potrebbe ancora includere i propri cookie nella richiesta.

Credenziali

In .NET per le app di Windows 8.x le proprietà HttpClientHandler.UseDefaultCredentials e HttpClientHandler.Credentials funzionano in modo indipendente. Inoltre, la proprietà Credentials accetta qualsiasi oggetto che implementa l'interfaccia ICredentials . In .NET Native, impostare la proprietà UseDefaultCredentials su true fa sì che Credentials la proprietà diventi null. Inoltre, la proprietà Credentials può essere impostata solo su null, DefaultCredentialso un oggetto di tipo NetworkCredential. L'assegnazione di qualsiasi altro oggetto ICredentials , il più popolare dei quali è CredentialCache, alla proprietà Credentials genera una PlatformNotSupportedException.

Altre funzionalità non supportate o non configurabili

In .NET Native:

Differenze di interoperabilità

API deprecate

Una serie di API usate con minore frequenza per l'interoperabilità con codice gestito è stata deprecata. Se usate con .NET Native, queste API possono generare un'eccezione NotImplementedException o PlatformNotSupportedException oppure produrre un errore del compilatore. In .NET per le app di Windows 8.x queste API vengono contrassegnate come obsolete, anche se la chiamata genera un avviso del compilatore invece di un errore del compilatore.

Le API deprecate VARIANT per il marshalling includono:

UnmanagedType.Struct è supportata, ma genera un'eccezione in alcuni scenari, ad esempio quando viene usata con IDispatch o varianti byref .

Le API deprecate per il supporto di IDispatch includono:

Le API deprecate per gli eventi COM classici includono:

Le API deprecate nell'interfaccia System.Runtime.InteropServices.ICustomQueryInterface, che non sono supportate in .NET Native, includono:

Altre funzionalità di interoperabilità non supportate includono:

API di marshalling usate raramente:

Compatibilità platform invoke e interoperabilità COM

La maggior parte dei scenari di platform invoke e interoperabilità COM sono ancora supportati in .NET Native. In particolare, sono supportate tutte le API di interoperabilità con Windows Runtime (WinRT) e tutti i marshalling richiesti per Windows Runtime. Ciò include il supporto del marshalling per:

Tuttavia, .NET Native non supporta quanto segue:

L'uso della reflection per richiamare un metodo platform invoke non è supportato. È possibile aggirare questa limitazione eseguendo il wrapping della chiamata al metodo in un altro metodo e usando la reflection per chiamare invece il wrapper.

Altre differenze rispetto alle API .NET per le app di Windows 8.x

In questa sezione sono elencate le API rimanenti che non sono supportate in .NET Native. Il set più grande delle API non supportate è rappresentato dalle API di Windows Communication Foundation (WCF).

DataAnnotations (System.ComponentModel.DataAnnotations)

I tipi degli spazi System.ComponentModel.DataAnnotations e dei nomi System.ComponentModel.DataAnnotations.Schema non sono supportati in .NET Native. Tra questi sono inclusi i tipi seguenti presenti in .NET per le app di Windows 8.x:

Visual Basic

Visual Basic non è attualmente supportato in .NET Native. I seguenti tipi negli spazi dei nomi Microsoft.VisualBasic e Microsoft.VisualBasic.CompilerServices non sono disponibili in .NET Native:

Contesto Reflection (spazio dei nomi System.Reflection.Context)

La classe System.Reflection.Context.CustomReflectionContext non è supportata in .NET Native.

RTC (System.Net.Http.Rtc)

La classe System.Net.Http.RtcRequestFactory non è supportata in .NET Native.

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

I tipi negli spazi dei nomi System.ServiceModel.* non sono supportati in .NET Native. Questi includono i tipi seguenti:

Differenze nei serializzatori

Le differenze riportate di seguito riguardano la serializzazione e la deserializzazione con le classi DataContractSerializer, DataContractJsonSerializere XmlSerializer :

Differenze di Visual Studio

Eccezioni e debug

Quando si eseguono app compilate usando .NET Native nel debugger, le eccezioni first-chance sono abilitate per i tipi di eccezione seguenti:

Creazione di applicazioni

Usare gli strumenti di compilazione x86 usati per impostazione predefinita da Visual Studio. Non è consigliabile usare gli strumenti di MSBuild AMD64, disponibili in C:\Program Files (x86)\MSBuild\12.0\bin\amd64, perché possono creare problemi di compilazione.

Profiler

  • Il profiler della CPU di Visual Studio e il profiler della memoria XAML non visualizzano Just My Code correttamente.

  • Il profiler della memoria di XAML non visualizza in modo accurato i dati di heap gestito.

  • Il profiler della CPU non identifica correttamente i moduli e consente di visualizzare i nomi di funzione con prefisso.

Progetti di librerie unit test

L'abilitazione di .NET Native in una libreria di unit test per un progetto di app Windows 8.x non è supportata e causa l'esito negativo della compilazione del progetto.

Vedi anche