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


Анализатор совместимости платформ

Вы, вероятно, слышали девиз One .NET: единая единая платформа для создания любого типа приложения. Пакет SDK для .NET включает ASP.NET Core, Entity Framework Core, Windows Forms, WPF и ML.NET, а также будет добавлять поддержку для дополнительных платформ со временем. .NET 5+ стремится обеспечить интерфейс, в котором вам не нужно понять различные варианты .NET, но не пытается полностью абстрагировать базовую операционную систему (ОС). Вы по-прежнему сможете вызывать API для конкретной платформы, например P/Invokes и WinRT.

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

К дополнительным API относятся:

  • SupportedOSPlatformAttribute чтобы аннотировать API как зависящие от платформы, и UnsupportedOSPlatformAttribute аннотировать API как неподдерживаемые для определенной операционной системы. Эти атрибуты могут дополнительно включать номер версии и уже применены к некоторым API для конкретной платформы в основных библиотеках .NET.
  • Is<Platform>() и Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) статические System.OperatingSystem методы в классе для безопасного вызова API для конкретной платформы. Например, OperatingSystem.IsWindows() можно использовать для защиты вызова API для windows и OperatingSystem.IsWindowsVersionAtLeast() можно использовать для защиты вызова API, зависящего от версии Windows. Ознакомьтесь с этими примерами того, как эти методы можно использовать в качестве охранников ссылок на API для конкретной платформы.

Предпосылки

Анализатор совместимости платформы является одним из анализаторов качества кода Roslyn. Эти анализаторы включены в пакет SDK для .NET. Анализатор совместимости платформы включен по умолчанию только для проектов, ориентированных на net5.0 и более поздние версии. Однако его можно включить для проектов, предназначенных для других платформ.

Как анализатор определяет зависимость платформы

  • Неатрибутированный API считается работающим на всех ОС-платформах.

  • API, помеченный как [SupportedOSPlatform("platform")], считается переносимым только на указанную платформу и все платформы, которые являются её подмножеством.

    • Атрибут может применяться несколько раз, чтобы указать поддержку нескольких платформ, например [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Если платформа является подмножеством другой платформы, атрибут подразумевает, что платформа супермножества также поддерживается. Например, [SupportedOSPlatform("iOS")] указывает, что API поддерживается на iOS, а также на платформе-супермножество, MacCatalyst.
    • Анализатор выдает предупреждение , если на API для конкретной платформы ссылаются без соответствующего контекста платформы:
      • Предупреждает, если проект не предназначен для поддерживаемой платформы (например, API для конкретного Windows, вызываемого из проекта, предназначенного для iOS <TargetFramework>net5.0-ios14.0</TargetFramework>).
      • Предупреждает, если проект является кроссплатформенным и вызывает API для конкретной платформы (например, API, зависящий от Windows, вызванный из кроссплатформенного TFM <TargetFramework>net5.0</TargetFramework>).
      • Не предупреждает, если API для конкретной платформы используется в проекте, ориентированном на любую из указанных платформ (например, если API, специфичный для Windows, вызывается из проекта, который нацелен на Windows <TargetFramework>net5.0-windows</TargetFramework>, и в проекте включено создание файлов AssemblyInfo.cs).
      • Не предупреждает, если вызов API для конкретной платформы охраняется соответствующими методами проверки платформы (например, вызов API для windows, защищенный OperatingSystem.IsWindows()).
      • Не выдает предупреждение , если API для конкретной платформы используется в том же контексте для конкретной платформы (вызываемое место также связано с [SupportedOSPlatform("platform")).
  • API, помеченный как [UnsupportedOSPlatform("platform")], считается неподдерживаемым на указанной платформе и на всех платформах, которые являются её подмножествами, но поддерживается для всех других платформ.

    • Атрибут может применяться несколько раз с различными платформами, например [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")].
    • Если платформа является подмножеством другой платформы, атрибут подразумевает, что платформа супермножества также не поддерживается. Например, [UnsupportedOSPlatform("iOS")] указывает на то, что API не поддерживается на платформе iOS, а также на платформе MacCatalyst, которая является надмножеством.
    • Анализатор выдает предупреждение только в том случае, если platform он действует для места вызова:
      • Предупреждает, если проект нацелен на платформу, которая отмечена как неподдерживаемая (например, если API отмечен атрибутом [UnsupportedOSPlatform("windows")], а вызов происходит на платформе <TargetFramework>net5.0-windows</TargetFramework>).

      • Предупреждает, если проект нацелен на несколько платформ и platform включен в группу элементов MSBuild <SupportedPlatform> по умолчанию, или platform вручную включён в MSBuild<группу элементов SupportedPlatform>:

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • Не предупреждает , если вы создаете приложение, которое не предназначено для неподдерживаемой платформы или является многоцелевой, а платформа не включена в группу элементов MSBuild <SupportedPlatform> по умолчанию.

  • Экземпляры обоих атрибутов могут быть созданы с номерами версий в составе имени платформы или без них. Номера версий находятся в формате major.minor[.build[.revision]]; major.minor являются обязательными и buildrevision необязательными. Например, "Windows6.1" обозначает Windows версии 6.1, но "Windows" интерпретируется как Windows 0.0.

Дополнительные сведения см. в примерах работы атрибутов и их диагностики.

Как анализатор распознает целевые платформы TFM

Анализатор не проверяет целевые платформы моникера целевой платформы (TFM) в свойствах MSBuild, таких как <TargetFramework> или <TargetFrameworks>. Если TFM имеет целевую платформу, MSBuild внедряет SupportedOSPlatform атрибут с именем целевой платформы в файл AssemblyInfo.cs , который используется анализатором. Например, если TFM равен net5.0-windows10.0.19041, MSBuild внедряет атрибут [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] в файл AssemblyInfo.cs, и вся сборка является только для Windows. Поэтому при вызове API-интерфейсов только для Windows с версией 7.0 или ниже никаких предупреждений в проекте не возникает.

Замечание

Если для проекта отключено создание файла AssemblyInfo.cs (т. е. свойству <GenerateAssemblyInfo> присвоено значение false), MSBuild не может добавить обязательный атрибут уровня SupportedOSPlatform сборки. В этом случае при использовании API для конкретной платформы могут возникать предупреждения, даже если эта платформа является целевой. Для устранения этих предупреждений активируйте создание файла AssemblyInfo.cs или добавьте в проект атрибут вручную.

Интеграция платформы

.NET 6 представила концепцию включения платформы, где одна платформа может быть подмножеством другой платформы. Аннотация для платформы-подмножества подразумевает ту же поддержку (или её отсутствие) для платформы-надмножества. Если метод проверки платформы в типе OperatingSystem имеет атрибут SupportedOSPlatformGuard("supersetPlatform")], то supersetPlatform считается супермножеством платформы ОС, для которой метод выполняет проверку.

Например, OperatingSystem.IsIOS() метод является атрибутом [SupportedOSPlatformGuard("MacCatalyst")]. Поэтому применяются следующие утверждения.

  • Методы OperatingSystem.IsIOS() и OperatingSystem.IsIOSVersionAtLeast проверяют не только платформу iOS, но и платформу MacCatalyst.
  • [SupportedOSPlatform("iOS")] подразумевает, что API поддерживается на платформе iOS и также на платформе её супермножества MacCatalyst. Вы можете использовать атрибут [UnsupportedOSPlatform("MacCatalyst")], чтобы исключить эту подразумеваемую поддержку.
  • [UnsupportedOSPlatform("iOS") подразумевает, что API не поддерживается на iOS и MacCatalyst. Можно использовать атрибут [SupportedOSPlatform("MacCatalyst")] для исключения подразумеваемой нехватки поддержки.

Рассмотрим следующую матрицу покрытия, где ✔️ указывается, что платформа поддерживается и ❌ указывает, что платформа не поддерживается.

Платформа SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
Подмножество ✔️ ✔️
Надмножество ✔️ ✔️ ✔️ ✔️

Подсказка

Те же правила применяются к атрибутам SupportedOSPlatformGuard и UnsupportedOSPlatformGuard.

В следующем фрагменте кода показано, как объединить атрибуты, чтобы задать правильный уровень поддержки.

  // MacCatalyst is a superset of iOS therefore supported on iOS and MacCatalyst
  [SupportedOSPlatform("iOS")]
  public void ApiOnlySupportedOnIOSAndMacCatalyst() { }

  // Does not imply iOS, only supported on MacCatalyst
  [SupportedOSPlatform("MacCatalyst")]
  public void ApiOnlySupportedOnMacCatalyst() { }

  [SupportedOSPlatform("iOS")] // Supported on iOS and MacCatalyst
  [UnsupportedOSPlatform("MacCatalyst")] // Removes implied MacCatalyst support
  public void ApiOnlySupportedOnIos() { }

  // Unsupported on iOS and MacCatalyst
  [UnsupportedOSPlatform("iOS")]
  public void ApiUnsupportedOnIOSAndMacCatalyst();

  // Does not imply iOS, only unsupported on MacCatalyst
  [UnsupportedOSPlatform("MacCatalyst")]
  public void ApiUnsupportedOnMacCatalyst() { }

  [UnsupportedOSPlatform("iOS")] // Unsupported on iOS and MacCatalyst
  [SupportedOSPlatform("MacCatalyst")] // Removes implied MacCatalyst unsupportedness
  public void ApiUnsupportedOnIos() { }

Расширенные сценарии для сочетаний атрибутов

  • Если присутствует сочетание [SupportedOSPlatform] атрибутов и [UnsupportedOSPlatform] атрибутов, все атрибуты группируются по идентификатору платформы ОС:

    • Поддерживаются только списки Если самая ранняя версия для каждой платформы ОС задана атрибутом [SupportedOSPlatform], API считается таким, который поддерживается только указанными платформами и не поддерживается всеми другими. Необязательные [UnsupportedOSPlatform] атрибуты для каждой платформы могут иметь только более высокую версию минимально поддерживаемой версии, которая указывает, что API удаляется начиная с указанной версии.

      // API is only supported on Windows from version 6.2 to 10.0.19041.0 and all versions of Linux
      // The API is considered not supported for all other platforms.
      [SupportedOSPlatform("windows6.2")]
      [UnsupportedOSPlatform("windows10.0.19041.0")]
      [SupportedOSPlatform("linux")]
      public void ApiSupportedFromWindows80SupportFromCertainVersion();
      
    • Список только для неподдерживаемых. Если самая ранняя версия для каждой платформы ОС задана атрибутом [UnsupportedOSPlatform], API считается таким, который не поддерживается только указанными платформами и поддерживается всеми другими. Список может иметь [SupportedOSPlatform] атрибут с той же платформой, но более поздней версией, которая означает, что API поддерживается начиная с этой версии.

      // The API is unsupported on all Linux versions was unsupported on Windows until version 10.0.19041.0.
      // The API is considered supported everywhere else without constraints.
      [UnsupportedOSPlatform("windows")]
      [SupportedOSPlatform("windows10.0.19041.0")]
      [UnsupportedOSPlatform("linux")]
      public void ApiSupportedFromWindows8UnsupportedFromWindows10();
      
    • Список "Несогласованные". Если самая низкая версия для некоторых платформ [SupportedOSPlatform], а для других платформ [UnsupportedOSPlatform], это считается несоответствием, которое анализатором не поддерживается. Если возникает несоответствие, анализатор игнорирует [UnsupportedOSPlatform] платформы.

      • Если самые низкие версии атрибутов [SupportedOSPlatform] и [UnsupportedOSPlatform] равны, анализатор рассматривает платформу как часть списка только поддерживаемых.
  • Атрибуты платформы можно применять к типам, элементам (методам, полям, свойствам и событиям) и сборкам с различными именами платформ или версиями.

    • Атрибуты, примененные на верхнем уровне target , влияют на все его члены и типы.
    • Атрибуты дочернего уровня применяются только в том случае, если они соответствуют правилу "дочерние аннотации могут сузить поддерживаемые платформы, но они не могут расширить её".
      • Если у родителя есть список только поддерживаемых платформ, тогда дочерние атрибуты членов не могут добавлять новую поддержку платформы, так как это расширило бы родительскую поддержку. Поддержку новой платформы можно добавить только в родительскую. Но дочерний Supported элемент может иметь атрибут для той же платформы в более поздних версиях, так как это ограничивает поддержку. Кроме того, дочерний элемент может иметь Unsupported атрибут с той же платформой, что также сужает родительскую поддержку.
      • Если родительский элемент имеет только неподдерживаемый список, дочерние атрибуты-члены могут добавить поддержку новой платформы, так как это сужает родительскую поддержку. Но он не может иметь атрибут Supported для той же платформы, что и родительский элемент, так как это продлевает поддержку родительского элемента. Поддержку той же платформы можно добавить только в родительский элемент, где был применен исходный Unsupported атрибут.
    • Если [SupportedOSPlatform("platformVersion")] применяется несколько раз для API с тем же platform именем, анализатор рассматривает только одну с минимальной версией.
    • Если [UnsupportedOSPlatform("platformVersion")] применяется более двух раз для API с platform одинаковым именем, анализатор рассматривает только два с самыми ранними версиями.

    Замечание

    API, поддерживаемый изначально, но впоследствии неподдерживаемый (удалённый) в более поздней версии, не ожидается, что будет повторно поддержан в ещё более поздней версии.

Примеры того, как работают атрибуты, и диагностика, которую они производят.

// An API supported only on Windows all versions.
[SupportedOSPlatform("Windows")]
public void WindowsOnlyApi() { }

// an API supported on Windows and Linux.
[SupportedOSPlatform("Windows")]
[SupportedOSPlatform("Linux")]
public void SupportedOnWindowsAndLinuxOnly() { }

// an API only supported on Windows 6.2 and later, not supported for all other.
// an API is removed/unsupported from version 10.0.19041.0.
[SupportedOSPlatform("windows6.2")]
[UnsupportedOSPlatform("windows10.0.19041.0")]
public void ApiSupportedFromWindows8UnsupportedFromWindows10() { }

// an Assembly supported on Windows, the API added from version 10.0.19041.0.
[assembly: SupportedOSPlatform("Windows")]
[SupportedOSPlatform("windows10.0.19041.0")]
public void AssemblySupportedOnWindowsApiSupportedFromWindows10() { }

public void Caller()
{
    WindowsOnlyApi(); // warns: This call site is reachable on all platforms. 'WindowsOnlyApi()' is only supported on: 'windows'

    // This call site is reachable on all platforms. 'SupportedOnWindowsAndLinuxOnly()' is only supported on: 'Windows', 'Linux'
    SupportedOnWindowsAndLinuxOnly();

    // This call site is reachable on all platforms. 'ApiSupportedFromWindows8UnsupportedFromWindows10()' is only supported on: 'windows' from version 6.2 to 10.0.19041.0
    ApiSupportedFromWindows8UnsupportedFromWindows10();

    // for same platform analyzer only warn for the latest version.
    // This call site is reachable on all platforms. 'AssemblySupportedOnWindowsApiSupportedFromWindows10()' is only supported on: 'windows' 10.0.19041.0 and later
    AssemblySupportedOnWindowsApiSupportedFromWindows10();
}

// an API not supported on android but supported on all other.
[UnsupportedOSPlatform("android")]
public void DoesNotWorkOnAndroid() { }

// an API was unsupported on Windows until version 6.2.
// The API is considered supported everywhere else without constraints.
[UnsupportedOSPlatform("windows")]
[SupportedOSPlatform("windows6.2")]
public void StartedWindowsSupportFromVersion8() { }

// an API was unsupported on Windows until version 6.2.
// Then the API is removed (unsupported) from version 10.0.19041.0.
// The API is considered supported everywhere else without constraints.
[UnsupportedOSPlatform("windows")]
[SupportedOSPlatform("windows6.2")]
[UnsupportedOSPlatform("windows10.0.19041.0")]
public void StartedWindowsSupportFrom8UnsupportedFrom10() { }

public void Caller2()
{
    DoesNotWorkOnAndroid(); // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'

    // This call site is reachable on all platforms. 'StartedWindowsSupportFromVersion8()' is unsupported on: 'windows' 6.2 and before.
    StartedWindowsSupportFromVersion8();

    // This call site is reachable on all platforms. 'StartedWindowsSupportFrom8UnsupportedFrom10()' is supported on: 'windows' from version 6.2 to 10.0.19041.0
    StartedWindowsSupportFrom8UnsupportedFrom10();
}

Обработать предупреждения

Рекомендуемый способ справиться с этими диагностиками — убедиться, что при работе на соответствующей платформе можно вызывать только API для конкретной платформы. Ниже приведены параметры, которые можно использовать для устранения предупреждений; выберите наиболее подходящий вариант для вашей ситуации:

  • Защитите звонок. Это можно сделать, условно вызывая код во время выполнения. Проверьте, работаете ли вы в нужном Platform режиме с помощью одного из методов проверки платформы, например OperatingSystem.Is<Platform>() или OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0). Пример.

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

  • Утверждение сайта вызова с помощью проверки платформы. Если вы не хотите накладные расходы от дополнительной if инструкции во время выполнения, используйте Debug.Assert(Boolean). Пример.

  • Удалите код. Как правило, не то, что вы хотите, потому что это означает, что вы теряете точность при использовании кода пользователями Windows. В случаях, когда существует кроссплатформенная альтернатива, скорее всего, лучше использовать это через API для конкретной платформы.

  • Отключите предупреждение. Вы также можете просто отключить предупреждение с помощью записи EditorConfig или #pragma warning disable CA1416. Однако этот параметр должен быть последним средством при использовании API для конкретной платформы.

    Подсказка

    При отключении предупреждений с помощью директив предварительного компилятора #pragma идентификаторы, на которые вы нацелены, чувствительны к регистру. Например, ca1416 фактически не отключает предупреждение CA1416.

Ограждайте API, специфичные для платформы, с помощью методов проверки условий.

Имя платформы метода guard должно совпадать с именем платформы, зависящей от платформы API, использующей данную платформу. Если строка платформы вызывающего API включает версию:

  • Для атрибута [SupportedOSPlatform("platformVersion")] платформа метода guard version должна быть больше или равна платформе вызова Version.

  • Для атрибута [UnsupportedOSPlatform("platformVersion")] платформа version метода guard должна быть меньше или равна платформе вызывающего элемента Version.

    public void CallingSupportedOnlyApis() // Allow list calls
    {
        if (OperatingSystem.IsWindows())
        {
            WindowsOnlyApi(); // will not warn
        }
    
        if (OperatingSystem.IsLinux())
        {
            SupportedOnWindowsAndLinuxOnly(); // will not warn, within one of the supported context
        }
    
        // Can use &&, || logical operators to guard combined attributes
        if (OperatingSystem.IsWindowsVersionAtLeast(6, 2) && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)))
        {
            ApiSupportedFromWindows8UnsupportedFromWindows10();
        }
    
        if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041, 0))
        {
            AssemblySupportedOnWindowsApiSupportedFromWindows10(); // Only need to check latest supported version
        }
    }
    
    public void CallingUnsupportedApis()
    {
        if (!OperatingSystem.IsAndroid())
        {
            DoesNotWorkOnAndroid(); // will not warn
        }
    
        if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(6, 2))
        {
            StartedWindowsSupportFromVersion8(); // will not warn
        }
    
        if (!OperatingSystem.IsWindows() || // supported all other platforms
           (OperatingSystem.IsWindowsVersionAtLeast(6, 2) && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)))
        {
            StartedWindowsSupportFrom8UnsupportedFrom10(); // will not warn
        }
    }
    
  • Если вам нужно защитить код, предназначенный для netstandard или netcoreapp, где новые OperatingSystem API недоступны, можно использовать RuntimeInformation.IsOSPlatform API, и анализатор будет их учитывать. Но он не так оптимизирован, как новые API, добавленные в OperatingSystem. Если платформа не поддерживается в OSPlatform структуре, можно вызвать OSPlatform.Create(String) и передать имя платформы, которое также учитывает анализатор.

    public void CallingSupportedOnlyApis()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            SupportedOnWindowsAndLinuxOnly(); // will not warn
        }
    
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("browser")))
        {
            ApiOnlySupportedOnBrowser(); // call of browser specific API
        }
    }
    

Аннотируйте API атрибутами платформенной защиты и используйте их в качестве настраиваемой защиты.

Как показано ранее, анализатор распознает статические методы platform-guard в OperatingSystem типе, например OperatingSystem.IsWindows, а также RuntimeInformation.IsOSPlatform. Однако вам может потребоваться кэшировать результат проверки в поле и повторно использовать его или использовать пользовательские методы проверки для проверки платформы. Анализатору необходимо распознавать такие API, как пользовательские механизмы защиты, и не должен предупреждать о тех API, которые этими механизмами защищены. Атрибуты охранника были представлены в .NET 6 для поддержки этого сценария:

  • SupportedOSPlatformGuardAttribute аннотирует API, которые можно использовать в качестве защиты для API, аннотированных с SupportedOSPlatformAttribute.
  • UnsupportedOSPlatformGuardAttribute аннотирует API, которые можно использовать в качестве защиты для API, аннотированных с UnsupportedOSPlatformAttribute.

Эти атрибуты могут дополнительно включать номер версии. Они могут применяться несколько раз для защиты нескольких платформ и могут использоваться для аннотирования поля, свойства или метода.

class Test
{
    [UnsupportedOSPlatformGuard("browser")] // The platform guard attribute
#if TARGET_BROWSER
    internal bool IsSupported => false;
#else
    internal bool IsSupported => true;
#endif

    [UnsupportedOSPlatform("browser")]
    void ApiNotSupportedOnBrowser() { }

    void M1()
    {
        ApiNotSupportedOnBrowser();  // Warns: This call site is reachable on all platforms.'ApiNotSupportedOnBrowser()' is unsupported on: 'browser'

        if (IsSupported)
        {
            ApiNotSupportedOnBrowser();  // Not warn
        }
    }

    [SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("Linux")]
    void ApiOnlyWorkOnWindowsLinux() { }

    [SupportedOSPlatformGuard("Linux")]
    [SupportedOSPlatformGuard("Windows")]
    private readonly bool _isWindowOrLinux = OperatingSystem.IsLinux() || OperatingSystem.IsWindows();

    void M2()
    {
        ApiOnlyWorkOnWindowsLinux();  // This call site is reachable on all platforms.'ApiOnlyWorkOnWindowsLinux()' is only supported on: 'Linux', 'Windows'.

        if (_isWindowOrLinux)
        {
            ApiOnlyWorkOnWindowsLinux();  // Not warn
        }
    }
}

Отметьте место вызова как специфичное для платформы

Имена платформ должны соответствовать API, зависящей от вызываемой платформы. Если строка платформы содержит версию:

  • Для атрибута [SupportedOSPlatform("platformVersion")] платформа вызова сайта version должна быть больше или равна платформе, с которой осуществляется вызов Version.

  • Для атрибута [UnsupportedOSPlatform("platformVersion")] платформа version у сайта вызова должна быть меньше или равна вызывающей платформе Version.

    // an API supported only on Windows.
    [SupportedOSPlatform("windows")]
    public void WindowsOnlyApi() { }
    
    // an API supported on Windows and Linux.
    [SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("Linux")]
    public void SupportedOnWindowsAndLinuxOnly() { }
    
    // an API only supported on Windows 6.2 and later, not supported for all other.
    // an API is removed/unsupported from version 10.0.19041.0.
    [SupportedOSPlatform("windows6.2")]
    [UnsupportedOSPlatform("windows10.0.19041.0")]
    public void ApiSupportedFromWindows8UnsupportedFromWindows10() { }
    
    // an Assembly supported on Windows, the API added from version 10.0.19041.0.
    [assembly: SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("windows10.0.19041.0")]
    public void AssemblySupportedOnWindowsApiSupportedFromWindows10() { }
    
    [SupportedOSPlatform("windows6.2")] // call site attributed Windows 6.2 or above.
    public void Caller()
    {
        WindowsOnlyApi(); // will not warn as call site is for Windows.
    
        // will not warn as call site is for Windows all versions.
        SupportedOnWindowsAndLinuxOnly();
    
        // will not warn for the [SupportedOSPlatform("windows6.2")] attribute, but warns for [UnsupportedOSPlatform("windows10.0.19041.0")]
        // This call site is reachable on: 'windows' 6.2 and later. 'ApiSupportedFromWindows8UnsupportedFromWindows10()' is unsupported on: 'windows' 10.0.19041.0 and later.
        ApiSupportedFromWindows8UnsupportedFromWindows10();
    
        // The call site version is lower than the calling version, so warns:
        // This call site is reachable on: 'windows' 6.2 and later. 'AssemblySupportedOnWindowsApiSupportedFromWindows10()' is only supported on: 'windows' 10.0.19041.0 and later
        AssemblySupportedOnWindowsApiSupportedFromWindows10();
    }
    
    [SupportedOSPlatform("windows10.0.22000")] // call site attributed with windows 10.0.22000 or above.
    public void Caller2()
    {
        // This call site is reachable on: 'windows' 10.0.22000 and later. 'ApiSupportedFromWindows8UnsupportedFromWindows10()' is unsupported on: 'windows' 10.0.19041.0 and later.
        ApiSupportedFromWindows8UnsupportedFromWindows10();
    
        // will not warn as call site version higher than calling API.
        AssemblySupportedOnWindowsApiSupportedFromWindows10();
    }
    
    [SupportedOSPlatform("windows6.2")]
    [UnsupportedOSPlatform("windows10.0.19041.0")] // call site supports Windows from version 6.2 to 10.0.19041.0.
    public void Caller3()
    {
        // will not warn as caller has exact same attributes.
        ApiSupportedFromWindows8UnsupportedFromWindows10();
    
        // The call site reachable for the version not supported in the calling API, therefore warns:
        // This call site is reachable on: 'windows' from version 6.2 to 10.0.19041.0. 'AssemblySupportedOnWindowsApiSupportedFromWindows10()' is only supported on: 'windows' 10.0.19041.0 and later.
        AssemblySupportedOnWindowsApiSupportedFromWindows10();
    }
    
    // an API not supported on Android but supported on all other.
    [UnsupportedOSPlatform("android")]
    public void DoesNotWorkOnAndroid() { }
    
    // an API was unsupported on Windows until version 6.2.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows6.2")]
    public void StartedWindowsSupportFromVersion8() { }
    
    // an API was unsupported on Windows until version 6.2.
    // Then the API is removed (unsupported) from version 10.0.19041.0.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows6.2")]
    [UnsupportedOSPlatform("windows10.0.19041.0")]
    public void StartedWindowsSupportFrom8UnsupportedFrom10() { }
    
    [UnsupportedOSPlatform("windows")] // Caller no support Windows for any version.
    public void Caller4()
    {
        // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'
        DoesNotWorkOnAndroid();
    
        // will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFromVersion8();
    
        // same, will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFrom8UnsupportedFrom10();
    }
    
    [UnsupportedOSPlatform("windows")]
    [UnsupportedOSPlatform("android")] // Caller not support Windows and Android for any version.
    public void Caller4()
    {
        DoesNotWorkOnAndroid(); // will not warn as call site not supports Android.
    
        // will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFromVersion8();
    
        // same, will not warns as the call site not support Windows at all, but supports all other.
        StartedWindowsSupportFrom8UnsupportedFrom10();
    }
    

Утверждение сайта вызова с помощью проверки платформы

Все условные проверки, используемые в примерах защиты платформы , также можно использовать в качестве условия Debug.Assert(Boolean).

// An API supported only on Linux.
[SupportedOSPlatform("linux")]
public void LinuxOnlyApi() { }

public void Caller()
{
    Debug.Assert(OperatingSystem.IsLinux());

    LinuxOnlyApi(); // will not warn
}

См. также