Поделиться через


Перенос приложения 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 HttpClientHandler класс внутренне использует WinINet (через HttpBaseProtocolFilter класс) вместо WebRequest WebResponse классов, используемых в стандартных приложениях .NET для Windows 8.x. WinINet не поддерживает все параметры конфигурации, которые поддерживает класс HttpClientHandler . В результате:

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

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

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

Proxy

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

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

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

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

Приложения .NET для Windows 8.x позволяют задать HttpClientHandler.AutomaticDecompression для свойства Deflateзначение , GZipкак, так Deflate и GZip.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 HttpClientHandler.Credentials .NET для Windows 8.x свойства работают независимо. Кроме того, свойство Credentials принимает любой объект, реализующий интерфейс ICredentials . В .NET Native указать UseDefaultCredentials свойство, которое приведет Credentials к тому, что true свойство станет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 не поддерживается и приводит к сбою сборки проекта.

См. также