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

.NET — это единая платформа для создания любого типа приложения. Он стремится создать условия, в которых вам не нужно разбираться в различных версиях .NET, но не пытается полностью скрыть базовую операционную систему (ОС). Вы можете продолжать вызывать API для конкретной платформы, например P/Invokes и WinRT.

Но использование API для конкретной платформы в компоненте означает, что код больше не работает на всех платформах. Анализатор совместимости платформы и дополнительные 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)
Подмножество ✔️ ✔️
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
}

См. также