Разработка для различных платформ

Современная версия .NET поддерживает различные операционные системы и устройства. Важно, чтобы библиотеки .NET с открытым кодом обеспечивали поддержку максимального спектра разработок, будь то веб-сайт, созданный на ASP.NET и размещенный в Azure, или .NET- игра на Unity.

Целевые объекты .NET и .NET Standard

Целевые объекты .NET и .NET Standard — лучший способ добавить кроссплатформенную поддержку в библиотеку .NET.

  • .NET Standard — это спецификация API-интерфейсов .NET, которые доступны во всех реализациях .NET. Нацеливание на .NET Standard позволяет создавать библиотеки, которые могут использовать API-интерфейсы определенной версии .NET Standard, т. е. такие библиотеки могут использоваться на всех платформах, на которых реализуется определенная версия .NET Standard.
  • .NET 6-8 — это реализации .NET. Каждая версия — это один продукт с универсальным набором возможностей и API, которые можно использовать для классических приложений Windows и кроссплатформенных консольных приложений, облачных служб и веб-сайтов.

Дополнительные сведения о том, как .NET сравнивается с .NET Standard, см. в статье .NET 5 и .NET Standard.

.NET Standard

Если проект предназначен для .NET или .NET Standard и успешно компилируется, это не гарантирует успешное выполнение библиотеки на всех платформах:

  • API-интерфейсы для конкретных платформ не будут работать на других платформах. К примеру, Microsoft.Win32.Registry будет нормально работать в ОС Windows и вызывать исключение PlatformNotSupportedException в любой другой операционной системе.
  • API-интерфейсы могут работать по-разному. Например, поддерживающие рефлексию API-интерфейсы демонстрируют другие показатели производительности, если приложение использует компиляцию AOT на платформе iOS или UWP.

Совет

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

✔️ ️СЛЕДУЕТ в первую очередь указать целевую платформу netstandard2.0.

Большинство библиотек общего назначения не нуждаются в API за пределами .NET Standard 2.0. Платформу .NET Standard 2.0 поддерживают все современные платформы. Ее рекомендуется использовать всегда, когда нужно реализовать кроссплатформенность с помощью одной целевой платформы. Если вам не нужна поддержка платформа .NET Framework, можно также использовать .NET Standard 2.1.

✔️ Добавьте целевой объект или более позднюю версию net6.0 , если вам требуются новые API- интерфейсы, представленные в современной .NET.

Приложения .NET 6 и более поздних версий могут использовать целевой netstandard2.0 объект, поэтому net6.0 не требуется. Вы должны явно использовать net6.0net7.0более новые API .NET или net8.0 использовать более новые API.NET.

❌ НЕЖЕЛАТЕЛЬНО указывать целевую платформу netstandard1.x.

.NET Standard 1.x распространяется в виде детализированного набора пакетов NuGet, который создает большой пакет граф зависимостей и приводит к загрузке большого количества пакетов при сборке. Современные реализации .NET поддерживают .NET Standard 2.0. .NET Standard 1.x следует указывать, только если вам специально нужна более старая платформа.

✔️ СЛЕДУЕТ указать netstandard1.x, если вам требуется целевая платформа netstandard2.0.

Все платформы, которые поддерживают .NET Standard 2.0, будут использовать целевую платформу netstandard2.0, а граф пакетов будет меньшим. При этом старые платформы также будут работать, но использовать они будут целевую платформу netstandard1.x.

❌ НЕ СЛЕДУЕТ указывать целевую платформу .NET Standard, если библиотека зависит от модели приложений для определенной платформы.

Например, библиотека средств управления UWP зависит от модели приложений, которая доступна только для UWP. Определенные API модели приложений недоступны в .NET Standard.

Настройка для различных версий

Иногда из библиотек необходимо получить доступ к API-интерфейсам конкретной платформы. Лучший способ вызова API для конкретной платформы — использовать многоцелевой интерфейс, который создает проект для многих целевых платформ .NET, а не только для одного.

Чтобы пользователям не приходилось компилировать проект под разные платформы, старайтесь писать код под NET Standard плюс под еще одну или несколько определенных платформ. При использовании нескольких целевых сборок все сборки упаковываются в один пакет NuGet. Таким образом пользователи будут ссылаться на один пакет, а NuGet будет выбирать подходящую реализацию. Библиотека .NET Standard выступает в качестве резервной. Она используется всегда, за исключением случаев, когда пакет NuGet предлагает реализацию под определенную платформу. Многоплатформенное нацеливание позволяет использовать условную компиляцию кода и вызывать API-интерфейсы определенных платформ.

NuGet package with multiple assemblies

✔ РЕКОМЕНДУЕТСЯ (помимо нацеливания на .NET Standard) также указать реализации .NET.

Нацеливание на реализации .NET позволяет вызывать API-интерфейсы определенных платформ, которые не включены в .NET Standard.

При этом не стоит исключать .NET Standard. Вместо этого выдайте исключение из реализации и предложите использовать API, поддерживающие нужные возможности. Таким образом, библиотеку можно использовать в любом месте и поддерживать поддержку возможностей во время выполнения.

public static class GpsLocation
{
    // This project uses multi-targeting to expose device-specific APIs to .NET Standard.
    public static async Task<(double latitude, double longitude)> GetCoordinatesAsync()
    {
#if NET462
        return CallDotNetFrameworkApi();
#elif WINDOWS_UWP
        return CallUwpApi();
#else
        throw new PlatformNotSupportedException();
#endif
    }

    // Allows callers to check without having to catch PlatformNotSupportedException
    // or replicating the OS check.
    public static bool IsSupported
    {
        get
        {
#if NET462 || WINDOWS_UWP
            return true;
#else
            return false;
#endif
        }
    }
}

✔️ РАССМОТРИТе возможность многонацеливания, даже если исходный код одинаков для всех целевых объектов, если у проекта есть любая библиотека или зависимости пакетов.

Зависимые пакеты проекта ( прямые или подчиненные) могут использовать одни и те же API кода, которые упаковываются в разные версии зависимой сборки на целевую платформу. Добавление конкретных целевых объектов гарантирует, что пользователям не нужно добавлять или обновлять перенаправления привязки сборки.

❌ ИЗБЕГАЙТЕ многоцелевой и целевой платформы .NET Standard, если исходный код одинаков для всех целевых объектов, а проект не имеет библиотеки или зависимостей пакетов.

NuGet будет автоматически использовать сборку .NET Standard. Нацеливание на отдельные реализации .NET увеличивает размер файла *.nupkg, не давая взамен никаких преимуществ.

✔️ РЕКОМЕНДУЕТСЯ добавить целевую платформу для net462, если вы предлагаете целевую платформу netstandard2.0.

Некоторые проблемы с использованием .NET Standard 2.0 в .NET Framework были устраненные в .NET Framework версии 4.7.2. Вы можете улучшить интерфейс для разработчиков, которые по-прежнему находятся на платформа .NET Framework 4.6.2 - 4.7.1, предлагая им двоичный файл, созданный для платформа .NET Framework 4.6.2.

✔️ DO Распространение библиотеки с помощью пакета NuGet.

NuGet определит для разработчиков наиболее подходящую целевую платформу и избавит их от необходимости выбирать подходящую реализацию.

✔️ СЛЕДУЕТ использовать свойство TargetFrameworks файла проекта при многоплатформенном нацеливании.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!-- This project will output netstandard2.0 and net462 assemblies -->
    <TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
  </PropertyGroup>
</Project>

✔ РЕКОМЕНДУЕТСЯ использовать MSBuild.Sdk.Extras при многоплатформенном нацеливании на UWP и Xamarin, так как это значительно упрощает файл проекта.

❌ Избегайте изменения имени сборки или использования различных имен сборок для каждой библиотеки TFM. Из-за зависимостей между библиотеками мультинацеливание с различными именами сборок для каждого TFM может разорвать потребителей пакетов. Сборка должна иметь одинаковое имя для всех TFM.

Старые целевые платформы

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

❌ НЕ️ СЛЕДУЕТ добавлять целевую платформу переносимой библиотеки классов (PCL). Например, portable-net45+win8+wpa81+wp8.

.NET Standard предлагает современный способ поддержки кроссплатформенных библиотек .NET и полностью заменяет PCL.

❌ НЕ СЛЕДУЕТ добавлять поддержку платформ .NET, которые больше не поддерживаются. Например, SL4, WP.