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


Таргетинг на разных платформах

Современная версия .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-рефлексии демонстрируют различные характеристики производительности, если приложение использует предварительную компиляцию на платформах 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.0, net7.0, net8.0 или net9.0, когда хотите использовать более новые API .NET.

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

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

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

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

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

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

❌ НЕ публикуйте netstandard2.0, если ваш проект или зависимости имеют мультинаправленное назначение.

netstandard2.0 не является средой выполнения, а многоцелевые проекты предоставляют среду выполнения и специфические библиотеки, которые необходимы при запуске на других фреймворках.

Многоплатформенное целевое назначение

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

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

Пакет NuGet с несколькими сборками

✔️ Учитывайте возможность нацеливания на реализации .NET в дополнение к .NET Standard.

Нацеливание на реализации .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.

✔️ ДО распространяйте вашу библиотеку с помощью пакета 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>

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

Старые цели

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

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

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

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