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

Вероятно, вы слышали девиз "единой платформы .NET" — единая, унифицированная платформа для создания приложений любого типа. Пакет SDK для .NET 5 включает ASP.NET Core, Entity Framework Core, WinForms, WPF, Xamarin и ML.NET, а также будет добавлять поддержку для дополнительных платформ со временем. .NET 5 стремится обеспечить опыт, в котором вам не нужно понять различные варианты .NET, но не пытается полностью абстрагировать базовую операционную систему (ОС). Вы сможете и далее вызывать API, зависящие от платформы, например привязки P/Invokes, WinRT или привязки Xamarin для iOS и Android.

Но использование в компоненте 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. Начиная с .NET 5 эти анализаторы включены в пакет 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, вызываемого из окон <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 — это обязательная часть, а build и revision — необязательные. Например, "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 вставляет в файл AssemblyInfo.cs атрибут [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] и вся сборка считается относящейся только к 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() и методы проверка не только платформуiOS, но и платформу MacCatalystOperatingSystem.IsIOSVersionAtLeast.
  • [SupportedOSPlatform("iOS")] подразумевает, что API поддерживается iOS на платформе супермножества и MacCatalystна ней. Атрибут можно использовать [UnsupportedOSPlatform("MacCatalyst")] для исключения этой подразумеваемой поддержки.
  • [UnsupportedOSPlatform("iOS")подразумевает, что API не поддерживается и MacCatalystне поддерживаетсяiOS. Атрибут можно использовать [SupportedOSPlatform("MacCatalyst")] для исключения этого подразумеваемого отсутствия поддержки.

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

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

Совет

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

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

  // 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, зависящих от платформы, с помощью методов условий

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

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

  • Для атрибута [UnsupportedOSPlatform("platformVersion")] значение для платформы метода условия version должно быть меньше или равно значению 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, в которых новые API OperatingSystem недоступны, вы можете использовать API RuntimeInformation.IsOSPlatform, который обрабатывается анализатором. Но он менее производителен, чем 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 и используйте его в качестве настраиваемой защиты.

Как показано ранее, анализатор распознает статические методы platform-guard в OperatingSystem типе, например OperatingSystem.IsWindows, а также RuntimeInformation.IsOSPlatform. Однако может потребоваться кэшировать охрану в поле и повторно использовать его или использовать методы custom guard для проверка платформы. Анализатору необходимо распознать такие 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
}

См. также