Перенос приложения Windows 8.x в .NET Native

.NET Native обеспечивает статическую компиляцию приложений в Microsoft Store или на компьютере разработчика. Это отличается от динамической компиляции, выполняемой для приложений Windows 8.x (ранее называемых приложениями Microsoft Store) JIT-компилятором или генератором собственных образов (Ngen.exe) на устройстве. Несмотря на различия, .NET Native пытается поддерживать совместимость с .NET для приложений Windows 8.x. В большинстве случаев работа приложений .NET для Windows 8.x также работает с .NET Native. Тем не менее в некоторых случаях могут произойти изменения поведения. В этом документе рассматриваются различия между стандартными приложениями .NET для Windows 8.x и .NET Native в следующих областях:

Общие различия среды выполнения

  • Исключения, такие как TypeLoadException, которые создаются JIT-компилятором при запуске приложения в среде CLR, обычно приводят к ошибкам во время компиляции при обработке .NET Native.

  • Не вызывайте метод GC.WaitForPendingFinalizers из потока пользовательского интерфейса приложения. Это может привести к взаимоблокировке на .NET Native.

  • Не полагайтесь на порядок вызова конструктора статического класса. В .NET Native порядок вызова отличается от порядка в стандартной среде выполнения. (Даже со стандартной средой выполнения, не следует рассчитывать на порядок выполнения конструкторов статических классов.)

  • Бесконечный цикл без вызовов (например, while(true);) на любом потоке может привести к остановке приложения. Аналогичным образом, большие или бесконечные ожидания могут также привести приложение к остановке.

  • Некоторые универсальные циклы инициализации не вызывают исключений в .NET Native. Например, следующий код создает исключение TypeLoadException исключений в стандартной среде CLR. В .NET Native это не так.

    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();
       }
    }
    
  • В некоторых случаях .NET Native предоставляет различные реализации библиотек классов платформа .NET Framework. Объект, возвращенный из метода, всегда будет реализовать члены возвращаемого типа. Тем не менее, поскольку его резервная реализация отличается, может оказаться невозможным привести его к тому же набору типов, как это можно было бы сделать на платформах .NET Framework. Например, в некоторых случаях может оказаться невозможным привести объект интерфейса IEnumerable<T> , возвращенный такими методами как TypeInfo.DeclaredMembers или TypeInfo.DeclaredProperties , к T[].

  • Кэш WinInet не включен по умолчанию в .NET для приложений Windows 8.x, но он находится на .NET Native. Это повышает производительность, но сказывается на рабочем наборе. Не требуется никаких действий разработчика.

Различия динамического программирования

.NET Native статические ссылки в коде из платформа .NET Framework, чтобы сделать код приложения локальным для достижения максимальной производительности. Тем не менее, двоичные размеры должны оставаться небольшими, поэтому не удается подключить всю платформу .NET Framework. Компилятор .NET Native устраняет это ограничение с помощью средства уменьшения зависимостей, который удаляет ссылки на неиспользуемый код. Однако .NET Native может не поддерживать или создавать некоторые сведения о типах и коде, если эти сведения не могут быть выведены статически во время компиляции, а вместо этого извлекаются динамически во время выполнения.

.NET Native обеспечивает отражение и динамическое программирование. Однако не все типы можно пометить для отражения, так как это приведет к слишком большому размеру созданного кода (особенно потому, что поддерживается отражение общедоступных API в платформа .NET Framework). Компилятор .NET Native принимает разумные решения о том, какие типы должны поддерживать отражение, сохраняет метаданные и создает код только для этих типов.

Например, привязка данных требует, чтобы приложение обеспечивало сопоставление имен свойств с функциями. В приложениях .NET для Windows 8.x среда CLR автоматически использует отражение для предоставления этой возможности для управляемых типов и общедоступных машинных типов. В .NET Native компилятор автоматически включает метаданные для типов, к которым привязываются данные.

Компилятор .NET Native также может обрабатывать часто используемые универсальные типы, такие как List<T> и Dictionary<TKey,TValue>, которые работают без каких-либо указаний или директив. Ключевое слово dynamic также поддерживается в заданных пределах.

Примечание

При переносе приложения в .NET Native следует тщательно протестировать все пути к динамическому коду.

Для большинства разработчиков достаточно конфигурации по умолчанию для .NET Native, но некоторые разработчики могут захотеть точно настроить свои конфигурации с помощью файла директив среды выполнения (rd.xml). Кроме того, в некоторых случаях компилятор .NET Native не может определить, какие метаданные должны быть доступны для отражения, и полагается на указания, особенно в следующих случаях:

  • Некоторые конструкции, такие как Type.MakeGenericType и MethodInfo.MakeGenericMethod не удается определить статически.

  • Поскольку компилятор не может определить экземпляры, универсальный тип, который требуется отразить на нем должен быть указан директивами среды выполнения. Это необходимо не только потому, что весь код должен быть включен, но так же и вследствие того, что отражение на универсальных типах могут образовывать бесконечный цикл (например, при вызове универсального метода для универсального типа).

Примечание

Директивы среды выполнения определяются в файле директив среды выполнения (. rd.xml). Общие сведения об использовании этого файла см. в разделе Приступая к работе. Сведения о директивах среды выполнения см. в разделе Runtime Directives (rd.xml) Configuration File Reference.

.NET Native также включает средства профилирования, которые помогают разработчику определить, какие типы за пределами набора по умолчанию должны поддерживать отражение.

Существует ряд других различий, связанных с отражением, в поведении между приложениями .NET для Windows 8.x и .NET Native.

В .NET Native:

  • Отражение закрытых типов и членов в библиотеке классов платформы .NET Framework не поддерживается. Тем не менее, можно выполнить отражение на собственных закрытых типах и членах, а также типах и членах библиотек сторонних поставщиков.

  • Свойство ParameterInfo.HasDefaultValue корректно возвращает false для объекта ParameterInfo , который представляет возвращаемое значение. В приложениях .NET для Windows 8.x возвращается true. Промежуточный язык (IL) не поддерживает эту функцию напрямую, и интерпретация остается за языком.

  • Открытые члены на структурах RuntimeFieldHandle и RuntimeMethodHandle не поддерживаются. Эти типы поддерживаются только для LINQ, деревьев выражений и инициализации статического массива.

  • RuntimeReflectionExtensions.GetRuntimeProperties и RuntimeReflectionExtensions.GetRuntimeEvents включают скрытые члены в базовых классах и поэтому могут переопределяться без явного переопределения. Это также справедливо для других методов RuntimeReflectionExtensions.GetRuntime* .

  • Type.MakeArrayType и Type.MakeByRefType не сбой при попытке создать определенные сочетания (например, массив byref объектов).

  • Нельзя использовать отражение для вызова членов, которые содержат параметры указателя.

  • Чтобы получить или задать поле указателя, нельзя использовать отражение.

  • Если число аргументов неверно, а тип одного из аргументов неверный, .NET Native создает ArgumentException вместо TargetParameterCountException.

  • Обычно двоичная сериализация исключений не поддерживается. В результате несериализуемые объекты могут быть добавлены к словарю Exception.Data .

Неподдерживаемые сценарии и API-интерфейсы

В следующих разделах перечислены неподдерживаемые сценарии и интерфейсы API для общей разработки, взаимодействия и таких технологий, как HTTPClient и Windows Communication Foundation (WCF):

Различия общей разработки

Типы значений

  • При переопределении методов ValueType.Equals и ValueType.GetHashCode для типа значения не вызывайте реализации базового класса. В приложениях .NET для Windows 8.x эти методы зависят от отражения. Во время компиляции .NET Native создает реализацию, которая не зависит от отражения среды выполнения. Это означает, что если не переопределить эти два метода, они будут работать должным образом, так как .NET Native создает реализацию во время компиляции. Однако, переопределение этих методов с помощью вызова реализации базового класса приводит к возникновению исключения.

  • Типы значений, превышающие 1 мегабайт, не поддерживаются.

  • Типы значений не могут иметь конструктор без параметров в .NET Native. (C# и Visual Basic запрещают конструкторы без параметров для типов значений. Однако их можно создать в IL.)

Массивы

  • Массивы с нижней границей, отличной от нуля, не поддерживаются. Как правило, эти массивы создаются путем вызова перегрузки Array.CreateInstance(Type, Int32[], Int32[]) .

  • Динамическое создание многомерных массивов не поддерживается. Такие массивы обычно создаются путем вызова перегрузки метода Array.CreateInstance , который включает в себя параметр lengths , или же путем вызова метода Type.MakeArrayType(Int32) .

  • Многомерные массивы, имеющие четыре или более измерений не поддерживаются; т.е. их значение свойства Array.Rank равно или больше четырех. Вместо этого используйте ступенчатые массивы (массива массивов). Например array[x,y,z] является недопустимым, но array[x][y][z] нет.

  • Вариативность для многомерных массивов не поддерживается и вызывает исключение InvalidCastException во время выполнения.

Универсальные шаблоны

  • Расширения бесконечного универсального типа приводят к ошибке компилятора. Например, этот код вызывает ошибку при компиляции:

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

Указатели

  • Массивы указателей не поддерживается.

  • Чтобы получить или задать поле указателя, нельзя использовать отражение.

Сериализация

Атрибут KnownTypeAttribute(String) не поддерживается. Вместо этого используйте атрибут KnownTypeAttribute(Type) .

Ресурсы

Использование локализованных ресурсов с классом EventSource не поддерживается. Свойство EventSourceAttribute.LocalizationResources не определяет локализованные ресурсы.

Делегаты

Delegate.BeginInvoke и Delegate.EndInvoke не поддерживаются.

Различные API

  • Свойство TypeInfo.GUID создает исключение, PlatformNotSupportedException если GuidAttribute атрибут не применяется к типу. Идентификатор GUID используется в основном для поддержки модели COM.

  • Метод DateTime.Parse правильно анализирует строки, содержащие короткие даты в .NET Native. Однако он не поддерживает совместимость с некоторыми изменениями в синтаксическом анализе даты и времени.

  • BigInteger.ToString("E")правильно округляется в .NET Native. В некоторых версиях среды CLR, результирующая строка усекается вместо округления.

Различия HttpClient

В .NET Native класс внутренне использует WinINet (через HttpBaseProtocolFilter класс) вместо классов иWebResponse, HttpClientHandler используемых в стандартных WebRequest приложениях .NET для Windows 8.x. WinINet не поддерживает все параметры конфигурации, которые поддерживает класс HttpClientHandler . В результате имеем следующее:

  • Некоторые свойства возможностей при возврате HttpClientHandlerfalse при .NET Native, в то время как они возвращаются true в стандартной версии .NET для приложений Windows 8.x.

  • Некоторые методы доступа к свойствам get конфигурации всегда возвращают фиксированное значение для .NET Native, отличное от настраиваемого значения по умолчанию в .NET для приложений Windows 8.x.

В следующих подразделах описаны некоторые дополнительные различия в поведении.

Прокси

Класс HttpBaseProtocolFilter не поддерживает настройку или переопределение прокси-сервера для каждого запроса. Это означает, что все запросы на .NET Native использовать настроенный системой прокси-сервер или не использовать прокси-сервер в зависимости от значения HttpClientHandler.UseProxy свойства . В приложениях .NET для Windows 8.x прокси-сервер определяется свойством HttpClientHandler.Proxy . На .NET Native установка HttpClientHandler.Proxy значения, отличного null от , вызывает PlatformNotSupportedException исключение. Свойство HttpClientHandler.SupportsProxy возвращает .NET Nativefalse, а true в стандартном платформа .NET Framework для приложений Windows 8.x.

Автоматическое перенаправление

Класс HttpBaseProtocolFilter не позволяет настроить максимальное количество автоматических перенаправлений. Значение свойства по умолчанию равно 50 в стандартных приложениях HttpClientHandler.MaxAutomaticRedirections .NET для Windows 8.x и может быть изменено. На .NET Native значение этого свойства равно 10, и при попытке изменить его вызывается PlatformNotSupportedException исключение. Свойство HttpClientHandler.SupportsRedirectConfiguration возвращается false при .NET Native, тогда как оно возвращается true в .NET для приложений Windows 8.x.

Автоматическая распаковка

.NET для приложений Windows 8.x позволяет задать свойству HttpClientHandler.AutomaticDecompressionDeflateзначение , GZipи GZipDeflate , или None. .NET Native поддерживается Deflate только вместе с GZip, или None. При попытке задать свойство AutomaticDecompression только на Deflate или GZip происходит его автоматическое задание на оба Deflate и GZip.

Файлы "cookie"

Обработка файлов cookie выполняется одновременно с HttpClient и WinINet. Файлы cookie из CookieContainer объединяются вместе файла cookie в кэше WinINet cookie. Удаление файла cookie из CookieContainer запрещает HttpClient отправлять файл cookie, но если файл cookie уже был просмотрен WinINet и файлы "cookie" не были удалены пользователем, WinINet отправляет его. Не существует средств программного удаления файла cookie из WinINet с использованием API HttpClient, HttpClientHandlerили CookieContainer . Задание свойства HttpClientHandler.UseCookies на false вызывает только HttpClient , чтобы остановить отправку файлов "cookie"; WinINet может по-прежнему включить свои файлы cookie в запрос.

Учетные данные

В приложениях HttpClientHandler.UseDefaultCredentials .NET для Windows 8.x свойства и HttpClientHandler.Credentials работают независимо. Кроме того, свойство Credentials принимает любой объект, реализующий интерфейс ICredentials . В .NET Native установка UseDefaultCredentials свойства в true значение приведет к тому, что Credentials свойство станет null. Кроме этого, свойство Credentials может быть задано только в null, DefaultCredentialsили объект типа NetworkCredential. Назначение любого другого объекта ICredentials , наиболее популярный из которых CredentialCache, свойству Credentials вызывает исключение PlatformNotSupportedException.

Другие неподдерживаемые и ненастраиваемые функции

В .NET Native:

Различия взаимодействия

Устаревшие интерфейсы API

Не рекомендуется использовать несколько редко применяемых API-интерфейсов для взаимодействия с управляемым кодом. При использовании с .NET Native эти API могут вызвать NotImplementedException исключение или PlatformNotSupportedException или привести к ошибке компилятора. В приложениях .NET для Windows 8.x эти API помечены как устаревшие, хотя их вызов создает предупреждение компилятора, а не ошибку компилятора.

К устаревшим API для VARIANT маршалинга относятся:

UnmanagedType.Struct поддерживается, но в некоторых сценариях вызывает исключение, например при использовании с IDispatch или byref вариантами.

Нерекомендуемые API для поддержки IDispatch :

Нерекомендуемые API для классических COM-событий включают:

Нерекомендуемые API в интерфейсеSystem.Runtime.InteropServices.ICustomQueryInterface, которые не поддерживаются в .NET Native, включают:

Другие неподдерживаемые функции взаимодействия:

Редко используемые API маршалинга:

Вызов неуправляемого кода и совместимость взаимодействия COM

Большинство сценариев вызова платформы и COM-взаимодействия по-прежнему поддерживаются в .NET Native. В частности, поддерживаются все взаимодействия с API среды выполнения Windows (WinRT) и весь необходимый маршалинг для среды выполнения Windows. Это включает поддержку маршалинга:

Однако .NET Native не поддерживает следующее:

Использование отражения для вызова метода неуправляемого кода не поддерживается. Это ограничение можно обойти путем заключения вызова метода в другой метод, вместо этого используя вызов оболочки.

Другие отличия от API .NET для приложений Windows 8.x

В этом разделе перечислены остальные API, которые не поддерживаются в .NET Native. Самым большим набором неподдерживаемых API являются API Windows Communication Foundation (WCF).

DataAnnotations (System.ComponentModel.DataAnnotations)

Типы в System.ComponentModel.DataAnnotations пространствах имен и System.ComponentModel.DataAnnotations.Schema не поддерживаются в .NET Native. К ним относятся следующие типы, которые присутствуют в приложениях .NET для Windows 8.x:

Visual Basic

Visual Basic в настоящее время не поддерживается в .NET Native. Следующие типы в Microsoft.VisualBasic пространствах имен и Microsoft.VisualBasic.CompilerServices недоступны в .NET Native:

Контекст отражения (пространство имен System.Reflection.Context)

Класс System.Reflection.Context.CustomReflectionContext не поддерживается в .NET Native.

Часы реального времени (System.Net.Http.Rtc)

Класс System.Net.Http.RtcRequestFactory не поддерживается в .NET Native.

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

Типы в пространствах имен System.ServiceModel.* не поддерживаются в .NET Native. К ним относятся следующие типы:

Различия в сериализаторах

Существуют следующие различия, касающиеся сериализации и десериализации с классами DataContractSerializer, DataContractJsonSerializerи XmlSerializer :

Различия в Visual Studio

Исключения и отладка

При запуске приложений, скомпилированных с помощью .NET Native в отладчике, исключения первого случая включаются для следующих типов исключений:

Создание приложений

Используйте средства построения x 86, которые используются по умолчанию в Visual Studio. Не рекомендуется использование средств AMD64 MSBuild, которые находятся в C:\Program Files (x86)\MSBuild\12.0\bin\amd64; Это может создать проблемы построения.

Профилировщики

  • Профилировщик ЦП в Visual Studio и профилировщик памяти XAML неправильно отображают «только мой код».

  • Профилировщик памяти XAML неточно отображает данные управляемой кучи.

  • Профилировщик ЦП неправильно идентифицирует модули и отображает имена функций с префиксами.

Проекты модульных тестов библиотеки

Включение .NET Native в библиотеке модульных тестов для проекта приложения Windows 8.x не поддерживается и приводит к сбою сборки проекта.

См. также раздел