Udostępnij przez


Migrowanie aplikacji systemu Windows 8.x do platformy .NET Native

Platforma .NET Native udostępnia statyczną kompilację aplikacji w sklepie Microsoft Store lub na komputerze dewelopera. Różni się to od kompilacji dynamicznej wykonywanej dla aplikacji systemu Windows 8.x (wcześniej nazywanych aplikacjami ze sklepu Microsoft Store) przez kompilator just in time (JIT) lub Native Image Generator (Ngen.exe) na urządzeniu. Pomimo różnic program .NET Native próbuje zachować zgodność z .NET dla aplikacji systemu Windows 8.x. W większości rzeczy, które działają na platformie .NET dla aplikacji systemu Windows 8.x, działają również z platformą .NET Native. Jednak w niektórych przypadkach mogą wystąpić zmiany behawioralne. W tym dokumencie omówiono te różnice między standardowymi aplikacjami platformy .NET dla systemu Windows 8.x i platformą .NET Native w następujących obszarach:

Ogólne różnice w czasie wykonywania

  • Wyjątki, takie jak TypeLoadException, zgłaszane przez kompilator JIT, gdy aplikacja działa na środowisku CLR, zwykle prowadzą do błędów czasu kompilacji podczas przetwarzania przez .NET Native.

  • Nie należy wywoływać metody GC.WaitForPendingFinalizers z wątku interfejsu użytkownika aplikacji. Może to spowodować zakleszczenie w środowisku uruchomieniowym .NET Native.

  • Nie należy polegać na porządkowaniu wywołań konstruktora klasy statycznej. W programie .NET Native kolejność wywołań różni się od kolejności w standardowym środowisku uruchomieniowym. (Nawet w przypadku standardowego środowiska uruchomieniowego nie należy polegać na kolejności wykonywania konstruktorów klas statycznych).

  • Nieskończona pętla bez wywołania (na przykład while(true);) w dowolnym wątku może spowodować zatrzymanie aplikacji. Podobnie duże lub nieskończone oczekiwania mogą spowodować zatrzymanie aplikacji.

  • Niektóre ogólne cykle inicjowania nie zgłaszają wyjątków w programie .NET Native. Na przykład poniższy kod zgłasza wyjątek TypeLoadException dla standardowego środowiska CLR. W .NET Native to nie działa.

    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();
       }
    }
    
  • W niektórych przypadkach platforma .NET Native udostępnia różne implementacje bibliotek klas .NET Framework. Obiekt zwrócony z metody zawsze implementuje członków zwracanego typu. Jednak ponieważ jej implementacja zapasowa jest inna, może nie być w stanie rzutować jej do tego samego zestawu typów, co na innych platformach .NET Framework. Na przykład w niektórych przypadkach nie można rzutować obiekt interfejsu IEnumerable<T> zwróconego przez metody, takie jak TypeInfo.DeclaredMembers lub TypeInfo.DeclaredProperties, do T[].

  • Pamięć podręczna WinInet nie jest domyślnie włączona na platformie .NET dla aplikacji systemu Windows 8.x, ale jest na platformie .NET Native. Poprawia to wydajność, ale ma konsekwencje dla zestawu roboczego. Nie jest wymagana żadna akcja dewelopera.

Różnice w programowaniu dynamicznym

Platforma .NET Native statycznie łączy kod z .NET Framework, aby uczynić go lokalnym dla aplikacji i uzyskać maksymalną wydajność. Jednak rozmiary binarne muszą pozostać małe, więc nie można wprowadzać całego programu .NET Framework. Kompilator .NET Native rozwiązuje to ograniczenie przy użyciu reduktora zależności, który usuwa odwołania do nieużywanego kodu. Jednak platforma .NET Native może nie obsługiwać ani generować niektórych informacji o typie i kodzie, gdy te informacje nie mogą być wywnioskowane statycznie w czasie kompilacji, ale zamiast tego są pobierane dynamicznie w czasie wykonywania.

.NET Native umożliwia refleksję i programowanie dynamiczne. Jednak nie wszystkie typy można oznaczyć do odbicia, ponieważ spowoduje to zbyt duży rozmiar wygenerowanego kodu (zwłaszcza dlatego, że odzwierciedlanie publicznych interfejsów API w programie .NET Framework jest obsługiwane). Kompilator .NET Native wybiera inteligentne opcje dotyczące typów, które powinny obsługiwać odbicie, i przechowuje metadane i generuje kod tylko dla tych typów.

Na przykład powiązanie danych wymaga, aby aplikacja mogła mapować nazwy właściwości na funkcje. W aplikacjach platformy .NET dla systemu Windows 8.x środowisko uruchomieniowe języka wspólnego automatycznie używa odbicia w celu zapewnienia tej funkcji dla typów zarządzanych i publicznie dostępnych typów natywnych. W programie .NET Native kompilator automatycznie zawiera metadane typów, z którymi są powiązane dane.

Kompilator .NET Native może również obsługiwać powszechnie używane typy ogólne, takie jak List<T> i Dictionary<TKey,TValue>, które działają bez konieczności stosowania żadnych wskazówek lub dyrektyw. Słowo kluczowe dynamicznej jest również obsługiwane w ramach określonych limitów.

Uwaga / Notatka

Podczas przenoszenia aplikacji do platformy .NET Native należy dokładnie przetestować wszystkie dynamiczne ścieżki kodu.

Domyślna konfiguracja platformy .NET Native jest wystarczająca dla większości deweloperów, ale niektórzy deweloperzy mogą chcieć dostosować konfiguracje przy użyciu plików dyrektyw środowiska uruchomieniowego (.rd.xml). Ponadto w niektórych przypadkach kompilator .NET Native nie może określić, które metadane muszą być dostępne do odbicia i polegają na wskazówkach, szczególnie w następujących przypadkach:

  • Niektóre konstrukcje, takie jak Type.MakeGenericType i MethodInfo.MakeGenericMethod, nie można określić statycznie.

  • Ponieważ kompilator nie może określić wystąpień, typ ogólny, który chcesz odzwierciedlić, musi być określony przez dyrektywy środowiska uruchomieniowego. To nie tylko dlatego, że cały kod musi być włączony, ale także dlatego, że refleksja nad typami ogólnymi może tworzyć nieskończony cykl (na przykład, gdy metoda ogólna jest wywoływana na typie ogólnym).

Uwaga / Notatka

Dyrektywy środowiska uruchomieniowego są definiowane w plikach dyrektyw środowiska uruchomieniowego (.rd.xml). Aby uzyskać ogólne informacje na temat korzystania z tego pliku, zobacz Wprowadzenie. Aby uzyskać informacje na temat dyrektyw środowiska uruchomieniowego, zobacz Dyrektywy środowiska uruchomieniowego (rd.xml) Dokumentacja pliku konfiguracji.

Platforma .NET Native zawiera również narzędzia profilowania, które pomagają deweloperowi określić typy poza zestawem domyślnym, które powinny obsługiwać odbicie.

Istnieje wiele innych różnic związanych z refleksją w poszczególnych zachowaniach pomiędzy .NET dla aplikacji Windows 8.x a .NET Native.

W programie .NET Native:

  • Prywatna refleksja nad typami i członkami w bibliotece klas .NET Framework nie jest obsługiwana. Można jednak przeglądać własne prywatne typy i członków, a także typy i członków w bibliotekach innych firm.

  • Właściwość ParameterInfo.HasDefaultValue poprawnie zwraca false dla obiektu ParameterInfo, który reprezentuje wartość zwracaną. W przypadku aplikacji platformy .NET dla systemu Windows 8.x zwraca true. Język pośredni (IL) nie obsługuje tego bezpośrednio, a interpretacja pozostaje w języku.

  • Publiczni członkowie struktur RuntimeFieldHandle i RuntimeMethodHandle nie są obsługiwani. Te rodzaje są obsługiwane tylko dla LINQ, drzew wyrażeń oraz inicjalizacji statycznych tablic.

  • RuntimeReflectionExtensions.GetRuntimeProperties i RuntimeReflectionExtensions.GetRuntimeEvents zawierają ukryte elementy członkowskie w klasach bazowych, a tym samym mogą być zastępowane bez jawnych nadpisań. Dotyczy to również innych metod RuntimeReflectionExtensions.GetRuntime*.

  • Type.MakeArrayType i Type.MakeByRefType nie kończą się niepowodzeniem podczas próby utworzenia pewnych kombinacji (na przykład tablicy obiektów byref).

  • Nie można użyć refleksji do wywoływania członków, które mają parametry wskaźnikowe.

  • Nie można użyć odbicia, aby uzyskać lub ustawić pole wskaźnika.

  • Gdy liczba argumentów jest nieprawidłowa, a typ jednego z argumentów jest niepoprawny, program .NET Native zgłasza ArgumentException zamiast TargetParameterCountException.

  • Serializacja binarna wyjątków nie jest zwykle obsługiwana. W związku z tym do słownika Exception.Data można dodawać obiekty niesererowalne.

Nieobsługiwane scenariusze i interfejsy API

W poniższych sekcjach wymieniono nieobsługiwane scenariusze i interfejsy API dla ogólnych rozwiązań, międzyoperacyjności i technologii, takich jak HTTPClient i Windows Communication Foundation (WCF):

Ogólne różnice w rozwoju

typy wartości

  • Jeśli zastąpisz metody ValueType.Equals i ValueType.GetHashCode dla typu wartości, nie wywołaj implementacji klas bazowych. W aplikacjach platformy .NET dla systemu Windows 8.x te metody opierają się na odbiciu. W czasie kompilacji platforma .NET Native generuje implementację, która nie opiera się na odbiciu środowiska uruchomieniowego. Oznacza to, że jeśli te dwie metody nie zostaną zastąpione, będą działać zgodnie z oczekiwaniami, ponieważ platforma .NET Native generuje implementację w czasie kompilacji. Jednak nadpisanie tych metod i wywołanie implementacji klasy bazowej powoduje wyjątek.

  • Typy wartości większe niż 1 megabajt nie są obsługiwane.

  • Typy wartości nie mogą mieć konstruktora bez parametrów na platformie .NET Native. (C# i Visual Basic zabraniają konstruktorów bez parametrów w typach wartości. Można je jednak utworzyć w języku IL).

tablice

  • Tablice, których dolna granica jest inna niż zero, nie są obsługiwane. Zazwyczaj te tablice są tworzone przez wywołanie przeciążenia metody Array.CreateInstance(Type, Int32[], Int32[]).

  • Dynamiczne tworzenie tablic wielowymiarowych nie jest obsługiwane. Takie tablice są zwykle tworzone przez wywołanie przeciążenia metody Array.CreateInstance zawierającej parametr lengths lub przez wywołanie metody Type.MakeArrayType(Int32).

  • Tablice wielowymiarowe, które mają cztery lub więcej wymiarów, nie są obsługiwane; oznacza to, że wartość właściwości Array.Rank jest cztery lub większa. Zamiast tego użyj tablic postrzępionych (tablicy tablic). Na przykład array[x,y,z] jest nieprawidłowa, ale array[x][y][z] nie jest.

  • Wariancja dla tablic wielowymiarowych nie jest obsługiwana i powoduje wyjątek InvalidCastException w czasie wykonywania.

Typy ogólne

  • Nieskończone rozszerzenie typu ogólnego powoduje błąd kompilatora. Na przykład nie można skompilować tego kodu:

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

Wskaźniki

  • Tablice wskaźników nie są obsługiwane.

  • Nie można użyć odbicia, aby uzyskać lub ustawić pole wskaźnika.

Serializacja

Atrybut KnownTypeAttribute(String) nie jest obsługiwany. Zamiast tego użyj atrybutu KnownTypeAttribute(Type).

Zasoby

Użycie zlokalizowanych zasobów z klasą EventSource nie jest wspierane. Właściwość EventSourceAttribute.LocalizationResources nie definiuje zlokalizowanych zasobów.

Delegaci

Delegate.BeginInvoke i Delegate.EndInvoke nie są obsługiwane.

Różne interfejsy API

  • Właściwość TypeInfo.GUID zgłasza wyjątek PlatformNotSupportedException, jeśli atrybut GuidAttribute nie jest stosowany do typu. GUID jest używany głównie do obsługi modelu COM.

  • Metoda DateTime.Parse poprawnie analizuje ciągi zawierające daty krótkie w programie .NET Native. Jednak nie zachowuje zgodności z pewnymi zmianami w analizowaniu daty i godziny.

  • BigInteger.ToString ("E") jest poprawnie zaokrąglany w programie .NET Native. W niektórych wersjach środowiska CLR ciąg wynikowy jest obcinany zamiast zaokrąglony.

Różnice HttpClient

Na platformie .NET Native klasa HttpClientHandler wewnętrznie używa usługi WinINet (za pośrednictwem klasy HttpBaseProtocolFilter) zamiast klas WebRequest i WebResponse używanych w standardowej platformie .NET dla aplikacji systemu Windows 8.x. Usługa WinINet nie obsługuje wszystkich opcji konfiguracji, które obsługuje klasa HttpClientHandler. W efekcie:

  • Niektóre właściwości możliwości HttpClientHandler zwracają false na platformie .NET Native, natomiast zwracają true w standardowych aplikacjach .NET dla systemu Windows 8.x.

  • Niektóre metody dostępu do właściwości konfiguracji get na platformie .NET Native zawsze zwracają niezmienną wartość, która różni się od domyślnej wartości konfigurowalnej w platformie .NET dla aplikacji w systemie Windows 8.x.

Niektóre dodatkowe różnice w zachowaniu zostały omówione w poniższych podsekcjach.

Proxy

Klasa HttpBaseProtocolFilter nie obsługuje konfigurowania ani zastępowania serwera proxy dla poszczególnych żądań. Oznacza to, że wszystkie żądania na platformie .NET Native używają serwera proxy skonfigurowanego przez system lub nie używają żadnego serwera proxy, w zależności od wartości właściwości HttpClientHandler.UseProxy. Na platformie .NET dla aplikacji systemu Windows 8.x serwer proxy jest definiowany przez właściwość HttpClientHandler.Proxy. Na platformie .NET Native ustawienie HttpClientHandler.Proxy na wartość inną niż null zgłasza wyjątek PlatformNotSupportedException. Właściwość HttpClientHandler.SupportsProxy zwraca false na platformie .NET Native, natomiast zwraca true w standardowych aplikacjach .NET Framework dla systemu Windows 8.x.

automatyczne przekierowywanie

Klasa HttpBaseProtocolFilter nie zezwala na skonfigurowanie maksymalnej liczby automatycznych przekierowań. Wartość właściwości HttpClientHandler.MaxAutomaticRedirections wynosi domyślnie 50 w standardowym środowisku .NET dla aplikacji systemu Windows 8.x i można je modyfikować. Na platformie .NET Native wartość tej właściwości wynosi 10, a próba jej modyfikacji powoduje zgłoszenie wyjątku PlatformNotSupportedException. Właściwość HttpClientHandler.SupportsRedirectConfiguration zwraca wartość false na platformie .NET Native, natomiast zwraca true na platformie .NET dla aplikacji systemu Windows 8.x.

Automatyczna dekompresja

Platforma .NET dla systemu Windows 8.x umożliwia ustawienie właściwości HttpClientHandler.AutomaticDecompression na Deflate, GZip, zarówno Deflate, jak i GZiplub None. Platforma .NET Native obsługuje tylko Deflate razem z GZiplub None. Próba ustawienia właściwości AutomaticDecompression na wartość Deflate lub GZip sama dyskretnie ustawia ją na wartość Deflate i GZip.

Pliki cookie

Obsługa plików cookie jest wykonywana jednocześnie przez HttpClient i WinINet. Pliki cookie z CookieContainer są łączone z plikami cookie w pamięci podręcznej WinINet. Usunięcie pliku cookie z CookieContainer uniemożliwia HttpClient wysyłania pliku cookie, ale jeśli plik cookie był już widoczny przez WinINet, a pliki cookie nie zostały usunięte przez użytkownika, winINet go wyśle. Nie można programowo usunąć pliku cookie z sieci WinINet przy użyciu interfejsu API HttpClient, HttpClientHandlerlub CookieContainer. Ustawienie właściwości HttpClientHandler.UseCookies na false powoduje, że tylko HttpClient przestaje wysyłać pliki cookie, chociaż WinINet może nadal zawierać swoje pliki cookie w żądaniu.

Poświadczenia

W aplikacjach .NET dla systemu Windows 8.x właściwości HttpClientHandler.UseDefaultCredentials i HttpClientHandler.Credentials działają niezależnie. Ponadto właściwość Credentials akceptuje każdy obiekt implementujący interfejs ICredentials. W programie .NET Native ustawienie właściwości UseDefaultCredentials na true powoduje, że właściwość Credentials stanie się null. Ponadto właściwość Credentials można ustawić tylko na null, DefaultCredentialslub obiekt typu NetworkCredential. Przypisanie dowolnego innego obiektu ICredentials, z których najbardziej popularny jest CredentialCache, do właściwości Credentials generuje PlatformNotSupportedException.

inne nieobsługiwane lub nieskonfigurowalne funkcje

W programie .NET Native:

Różnice w interoperacyjności

przestarzałe API

Wiele rzadko używanych interfejsów API do współdziałania z kodem zarządzanym zostało przestarzałych. W przypadku użycia z platformą .NET Native te interfejsy API mogą zgłaszać wyjątek NotImplementedException lub PlatformNotSupportedException albo powodować błąd kompilatora. W przypadku aplikacji platformy .NET dla systemu Windows 8.x te interfejsy API są oznaczone jako przestarzałe, chociaż wywoływanie ich powoduje wygenerowanie ostrzeżenia kompilatora, a nie błędu kompilatora.

Przestarzałe interfejsy API do marshalingu VARIANT obejmują:

UnmanagedType.Struct jest obsługiwana, ale zgłasza wyjątek w niektórych scenariuszach, na przykład w przypadku użycia z wariantami IDispatch lub byref.

Przestarzałe interfejsy API dla obsługi IDispatch obejmują:

Przestarzałe interfejsy API dla klasycznych zdarzeń COM obejmują:

Przestarzałe interfejsy API w interfejsie System.Runtime.InteropServices.ICustomQueryInterface, który nie jest obsługiwany w programie .NET Native, obejmują:

Inne nieobsługiwane funkcje międzyoperacyjnych interfejsów obejmują:

Rzadko używane interfejsy API do marshalingu:

Wywołanie platformy i zgodność z interoperacyjnością COM

Większość scenariuszy międzyoperacyjności międzyplatformowych i modelu COM jest nadal obsługiwana na platformie .NET Native. W szczególności całe współdziałanie z interfejsami API środowiska uruchomieniowego systemu Windows (WinRT) i całe marshaling wymagane dla środowiska uruchomieniowego systemu Windows jest obsługiwane. Obejmuje to organizowanie wsparcia dla:

Jednak platforma .NET Native nie obsługuje następujących elementów:

Wywoływanie metody platformy P/Invoke przy użyciu refleksji nie jest obsługiwane. Można obejść to ograniczenie, opakowując wywołanie metody w innej metodzie i używając refleksji, aby wywołać opakowanie.

Inne różnice między interfejsami API platformy .NET dla aplikacji systemu Windows 8.x

W tej sekcji wymieniono pozostałe interfejsy API, które nie są obsługiwane na platformie .NET Native. Największym zestawem nieobsługiwanych interfejsów API są interfejsy API Windows Communication Foundation (WCF).

DataAnnotations (System.ComponentModel.DataAnnotations)

Typy w przestrzeniach nazw System.ComponentModel.DataAnnotations i System.ComponentModel.DataAnnotations.Schema nie są obsługiwane w programie .NET Native. Należą do nich następujące typy, które znajdują się na platformie .NET dla aplikacji systemu Windows 8.x:

Visual Basic

Język Visual Basic nie jest obecnie obsługiwany w programie .NET Native. Następujące typy w przestrzeniach nazw Microsoft.VisualBasic i Microsoft.VisualBasic.CompilerServices nie są dostępne na platformie .NET Native:

kontekst odbicia (System.Reflection.Context)

Klasa System.Reflection.Context.CustomReflectionContext nie jest obsługiwana w programie .NET Native.

RTC (System.Net.Http.Rtc)

Klasa System.Net.Http.RtcRequestFactory nie jest obsługiwana w programie .NET Native.

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

Typy w przestrzeniach nazw System.ServiceModel.* nie są obsługiwane w programie .NET Native. Należą do nich następujące typy:

Różnice w serializatorach

Następujące różnice dotyczą serializacji i deserializacji z klasami DataContractSerializer, DataContractJsonSerializeri XmlSerializer:

Różnice w programie Visual Studio

wyjątki i debugowanie

W przypadku uruchamiania aplikacji skompilowanych przy użyciu platformy .NET Native w debugerze wyjątki pierwszej szansy są włączone dla następujących typów wyjątków:

Tworzenie aplikacji

Użyj narzędzi kompilacji x86, które są domyślnie używane przez program Visual Studio. Nie zalecamy używania narzędzi MSBuild AMD64, które znajdują się w folderze C:\Program Files (x86)\MSBuild\12.0\bin\amd64; mogą one powodować problemy z kompilacją.

profilerzy

  • Profiler procesora CPU w Visual Studio i profiler pamięci XAML nie wyświetlają poprawnie Just-My-Code.

  • Profiler pamięci XAML nie wyświetla dokładnie danych sterty zarządzanej.

  • Profiler procesora CPU nie identyfikuje poprawnie modułów i wyświetla nazwy prefiksów funkcji.

projekty biblioteki testów jednostkowych

Włączenie platformy .NET Native w bibliotece testów jednostkowych dla projektu aplikacji systemu Windows 8.x nie jest obsługiwane i powoduje niepowodzenie kompilacji projektu.

Zobacz także