Analisador de compatibilidade de plataforma

Você provavelmente já ouviu o lema "Um .NET": uma plataforma única e unificada para criar qualquer tipo de aplicativo. O SDK do .NET 5 inclui ASP.NET Core, Entity Framework Core, WinForms, WPF, Xamarin e ML.NET e adicionará suporte para mais plataformas ao longo do tempo. O objetivo do .NET 5 é fornecer uma experiência em que não seja necessário pensar sobre os diferentes tipos de .NET, mas sem abstrair totalmente o SO (sistema operacional) subjacente. Ainda será possível chamar APIs específicas de uma plataforma, por exemplo, P/Invokes, WinRT ou as associações do Xamarin para iOS e Android.

Mas usar APIs específicas de uma plataforma em um componente significa que o código não funciona mais em todas as plataformas. Precisávamos detectar isso de alguma maneira no tempo de design, para que os desenvolvedores recebessem diagnósticos quando usassem inadvertidamente APIs específicas de uma plataforma. Pensando nisso, o .NET 5 apresenta o analisador de compatibilidade de plataforma e APIs complementares para ajudar os desenvolvedores a identificar e usar APIs específicas de uma plataforma quando apropriado.

As novas APIs incluem o seguinte:

  • SupportedOSPlatformAttribute para anotar APIs como específicas de uma plataforma e UnsupportedOSPlatformAttribute para anotar APIs como sem suporte em um determinado SO. Esses atributos podem incluir o número de versão e já foram aplicados a algumas APIs específicas de plataforma nas principais bibliotecas .NET.
  • Os métodos estáticos Is<Platform>() e Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) na classe System.OperatingSystem para chamar APIs específicas de uma plataforma com segurança. Por exemplo, OperatingSystem.IsWindows() pode ser usado para proteger uma chamada para uma API específica do Windows e OperatingSystem.IsWindowsVersionAtLeast() pode ser usado para proteger uma chamada de API específica do Windows com versão. Veja estes exemplos para saber como usar esses métodos como proteções de referências de APIs específicas de uma plataforma.

Pré-requisitos

O analisador de compatibilidade de plataforma é um dos analisadores de qualidade de código Roslyn. A partir do .NET 5, esses analisadores estão incluídos no SDK do .NET. O analisador de compatibilidade de plataforma é habilitado por padrão somente para projetos destinados a net5.0 ou a uma versão posterior. No entanto, é possível habilitá-lo para projetos destinados a outras estruturas.

Como o analisador determina a dependência de plataforma

  • Considera-se que uma API não atribuída funcione em todas as plataformas de SO.

  • Uma API marcada com [SupportedOSPlatform("platform")] é considerada portátil somente para a plataforma especificada e para todas as plataformas das quais ela é um subconjunto.

    • O atributo pode ser aplicado diversas vezes para indicar suporte de diversas plataformas, por exemplo, [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Se a plataforma for um subconjunto de outra, o atributo implicará que essa outra também terá suporte. Por exemplo, [SupportedOSPlatform("iOS")] implica que a API tem suporte em iOS e também em sua plataforma de superconjunto, MacCatalyst.
    • O analisador produzirá um aviso se as APIs específicas de uma plataforma forem referenciadas sem um contexto de plataforma adequado:
      • Avisa se o projeto não tem como destino a plataforma com suporte (por exemplo, uma API específica do Windows chamada de um projeto destinado ao iOS <TargetFramework>net5.0-ios14.0</TargetFramework>).
      • Avisa se o projeto é multiplataforma e se ele chama APIs específicas de uma plataforma (por exemplo, uma API específica do Windows chamada do TFM multiplataforma <TargetFramework>net5.0</TargetFramework>).
      • Não avisa se a API específica de uma plataforma é referenciada em um projeto destinado a qualquer uma das plataformas especificadas (por exemplo, para uma API específica do Windows chamada de um projeto destinado ao Windows<TargetFramework>net5.0-windows</TargetFramework> com a geração do arquivo AssemblyInfo.cs habilitada para o projeto).
      • Não avisa se a chamada à API específica de uma plataforma é protegida por métodos de verificação de plataforma correspondentes (por exemplo, uma chamada de API específica do Windows protegida por OperatingSystem.IsWindows()).
      • Não avisa se a API específica de uma plataforma é referenciada no mesmo contexto específico da plataforma (site de chamada também atribuído a [SupportedOSPlatform("platform")).
  • Uma API marcada com [UnsupportedOSPlatform("platform")] é considerada sem suporte na plataforma especificada e em qualquer plataforma da qual ela seja um subconjunto, mas é considerada com suporte para todas as outras plataformas.

    • O atributo pode ser aplicado diversas vezes com diferentes plataformas, por exemplo, [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")].
    • Se a plataforma for um subconjunto de outra, o atributo implicará que essa outra também não terá suporte. Por exemplo, [UnsupportedOSPlatform("iOS")] implica que a API não tem suporte em iOS e também em sua plataforma de superconjunto, MacCatalyst.
    • O analisador produzirá um aviso somente se o platform for efetivo para o site de chamada:
      • Avisa se o projeto tem como destino a plataforma atribuída como sem suporte (por exemplo, se a API for atribuída a [UnsupportedOSPlatform("windows")] e o site de chamada tiver <TargetFramework>net5.0-windows</TargetFramework> como destino).

      • Avisa se o projeto tem diversos destinos e platform é incluído no grupo de itens MSBuild <SupportedPlatform> padrão ou platform é incluído manualmente no grupo de itens MSBuild<SupportedPlatform>:

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • Não avisa se você está criando um aplicativo que não tem como destino a plataforma sem suporte ou que tem vários destinos e a plataforma não está incluída no grupo de itens MSBuild <SupportedPlatform> padrão.

  • É possível criar uma instância de ambos os atributos com ou sem números de versão como parte do nome da plataforma. Os números de versão estão no formato major.minor[.build[.revision]]; major.minor é necessário e as partes build e revision são opcionais. Por exemplo, "Windows6.1" indica Windows versão 6.1, mas "Windows" é interpretado como Windows 0.0.

Para saber mais, confira exemplos de como os atributos funcionam e quais diagnósticos eles causam.

Como o analisador reconhece plataformas de destino TFM

O analisador não verifica as plataformas de destino TFM (Moniker da Estrutura de Destino) nas propriedades do MSBuild, como <TargetFramework> ou <TargetFrameworks>. Se o TFM tiver uma plataforma de destino, o MSBuild injetará um atributo SupportedOSPlatform com o nome da plataforma de destino no arquivo AssemblyInfo.cs, que será consumido pelo analisador. Por exemplo, se o TFM for net5.0-windows10.0.19041, o MSBuild injetará o atributo [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] no arquivo AssemblyInfo.cs e todo o assembly será considerado somente para Windows. Portanto, chamar APIs somente Windows na versão 7.0 ou anterior não geraria avisos no projeto.

Observação

Se a geração do arquivo AssemblyInfo.cs estiver desabilitada para o projeto (ou seja, a propriedade <GenerateAssemblyInfo> foi definida como false), o atributo SupportedOSPlatform de nível de assembly necessário não poderá ser adicionado pelo MSBuild. Nesse caso, avisos podem ser exibidos para o uso de APIs específicas de uma plataforma, mesmo que você tenha essa plataforma como destino. Para resolver os avisos, habilite a geração do arquivo AssemblyInfo.cs ou adicione o atributo manualmente ao projeto.

Inclusão de plataforma

O .NET 6 apresenta o conceito de inclusão de plataforma, em que uma plataforma pode ser um subconjunto de outra. Uma anotação para a plataforma de subconjunto implica o mesmo suporte (ou a falta dele) para a plataforma de superconjunto. Se um método de verificação de plataforma no tipo OperatingSystem tiver um atributo SupportedOSPlatformGuard("supersetPlatform")], supersetPlatform será considerado um superconjunto da plataforma do SO que o método verifica.

Por exemplo, o método OperatingSystem.IsIOS() é atribuído a [SupportedOSPlatformGuard("MacCatalyst")]. Portanto, as seguintes afirmações se aplicam:

  • Os métodos OperatingSystem.IsIOS() e OperatingSystem.IsIOSVersionAtLeast verificam não somente a plataforma iOS, mas também a plataforma MacCatalyst.
  • [SupportedOSPlatform("iOS")] implica que a API tem suporte em iOS e também em sua plataforma de superconjunto, MacCatalyst. É possível usar o atributo [UnsupportedOSPlatform("MacCatalyst")] para excluir esse suporte implícito.
  • [UnsupportedOSPlatform("iOS") implica que a API não é compatível com iOS e MacCatalyst. É possível usar o atributo [SupportedOSPlatform("MacCatalyst")] para excluir esse suporte implícito.

Considere a seguinte matriz de cobertura, em que ✔️ indica que a plataforma é compatível e ❌ indica que a plataforma não é compatível.

Plataforma SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
Subconjunto ✔️ ✔️
Superconjunto ✔️ ✔️ ✔️ ✔️

Dica

As mesmas regras se aplicam aos atributos SupportedOSPlatformGuard e UnsupportedOSPlatformGuard.

O snippet de código a seguir mostra como combinar atributos para definir o nível de suporte correto.

  // 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() { }

Cenários avançados de combinações de atributos

  • Se houver uma combinação de atributos [SupportedOSPlatform] e [UnsupportedOSPlatform], todos os atributos serão agrupados pelo identificador de plataforma do SO:

    • Lista de produtos com suporte. Se a versão mais antiga de cada plataforma de SO for um atributo [SupportedOSPlatform], a API será considerada compatível apenas com as plataformas listadas e incompatível com todas as outras. Os atributos [UnsupportedOSPlatform] opcionais para cada plataforma só podem ter uma versão superior da versão mínima com suporte, o que denota que a API é removida a partir da versão especificada.

      // 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();
      
    • Lista de produtos sem suporte. Se a versão mais antiga de cada plataforma de SO for um atributo [UnsupportedOSPlatform], a API será considerada incompatível apenas com as plataformas listadas e compatível com todas as outras. A lista pode ter o atributo [SupportedOSPlatform] com a mesma plataforma, mas com uma versão superior, o que denota que a API é compatível a partir dessa versão.

      // 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();
      
    • Lista de inconsistências. Se a versão mais baixa para algumas plataformas for [SupportedOSPlatform] e para outras for [UnsupportedOSPlatform], isso será considerado inconsistente e não terá suporte no analisador. No caso de inconsistências, o analisador ignora as plataformas [UnsupportedOSPlatform].

      • Quando as versões mais baixas dos atributos [SupportedOSPlatform] e [UnsupportedOSPlatform] são iguais, o analisador considera a plataforma como parte da Lista de produtos com suporte.
  • Os atributos de plataforma podem ser aplicados a tipos, membros (métodos, campos, propriedades e eventos) e assemblies com diferentes nomes ou versões de plataforma.

    • Os atributos aplicados ao target de nível superior afetam todos os respectivos membros e tipos.
    • Os atributos de nível filho só se aplicam quando aderem à regra "anotações filho podem restringir o suporte de plataformas, mas não podem ampliá-lo".
      • Quando o pai tem uma lista de produtos com suporte, os atributos do membro filho não podem adicionar um novo suporte de plataforma, pois isso estenderia o suporte do pai. O suporte para uma nova plataforma só pode ser adicionado ao próprio pai. No entanto, o filho pode ter o atributo Supported para a mesma plataforma com versões posteriores, pois isso restringe o suporte. Além disso, o filho pode ter o atributo Unsupported com a mesma plataforma que também restringe o suporte do pai.
      • Quando o pai tem uma lista de produtos sem suporte, os atributos do membro filho podem adicionar o suporte para uma nova plataforma, pois isso restringe o suporte do pai. No entanto, não é possível ter o atributo Supported para a mesma plataforma que o pai, pois isso estenderia o suporte do pai. O suporte para a mesma plataforma só pode ser adicionado ao pai quando o atributo Unsupported original foi aplicado.
    • Quando [SupportedOSPlatform("platformVersion")] é aplicado mais de uma vez para uma API com o mesmo nome platform, o analisador considera somente a que corresponde à versão mínima.
    • Quando [UnsupportedOSPlatform("platformVersion")] é aplicado mais de duas vezes para uma API com o mesmo nome platform, o analisador considera as duas aplicações que correspondem à versão mínima.

    Observação

    Uma API que tinha suporte inicialmente, mas que teve esse suporte removido em uma versão posterior não deverá ser compatível novamente em uma versão ainda mais recente.

Exemplos de como os atributos funcionam e quais diagnósticos eles produzem

// 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();
}

Lidar com avisos relatados

A maneira recomendada de lidar com esses diagnósticos é garantir que somente as APIs específicas de uma plataforma sejam chamadas durante a execução nessa plataforma. Escolha a opção mais adequada para a sua situação entre as seguintes opções para lidar com avisos:

  • Proteja a chamada. É possível fazer isso chamando condicionalmente o código no runtime. Verifique se você está realizando a execução em um Platform desejado usando um dos métodos de verificação de plataforma, por exemplo, OperatingSystem.Is<Platform>() ou OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0). Exemplo.

  • Marque o site da chamada como específico da plataforma. Também é possível optar por marcar suas próprias APIs como específicas de uma plataforma, encaminhando efetivamente os requisitos para seus chamadores. Marque o método ou tipo contido ou todo o assembly com os mesmos atributos da chamada dependente de plataforma referenciada. Exemplos.

  • Declare o site da chamada com a verificação de plataforma. Para evitar a sobrecarga de uma instrução if adicional no runtime, use Debug.Assert(Boolean). Exemplo.

  • Exclua o código. Isso geralmente não é o que você deseja, pois significa que você perde a fidelidade quando o código é usado por usuários do Windows. Para os casos em que existe uma alternativa multiplataforma, é provavelmente melhor usá-la em vez das APIs específicas de plataforma.

  • Suprima o aviso. Também é possível simplesmente suprimir o aviso, seja por meio de uma entrada EditorConfig ou de #pragma warning disable CA1416. No entanto, essa opção deve ser o último recurso ao usar APIs específicas de plataforma.

    Dica

    Ao desabilitar os avisos usando as diretivas do pré-compilador #pragma, os identificadores que você tem como destino diferenciam maiúsculas de minúsculas. Por exemplo, ca1416 não desabilitaria o aviso CA1416.

Proteja as APIs específicas de plataforma com métodos de proteção

O nome da plataforma do método de proteção deve corresponder ao nome da plataforma da API de chamada dependente de plataforma. Se a cadeia de caracteres da plataforma da API de chamada incluir a versão:

  • Para o atributo [SupportedOSPlatform("platformVersion")], o version da plataforma do método de proteção deve ser maior ou igual ao Version da plataforma de chamada.

  • Para o atributo [UnsupportedOSPlatform("platformVersion")], o version da plataforma do método de proteção deve ser menor ou igual ao Version da plataforma de chamada.

    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
        }
    }
    
  • Se você precisar proteger o código direcionado a netstandard ou netcoreapp quando novas APIs OperatingSystem não estiverem disponíveis, a API RuntimeInformation.IsOSPlatform poderá ser usada e será respeitada pelo analisador. No entanto, ela não é tão otimizada quanto as novas APIs adicionadas em OperatingSystem. Se a plataforma não tiver suporte no struct OSPlatform, chame OSPlatform.Create(String) e transmita o nome da plataforma, que o analisador também respeitará.

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

Anotar APIs com atributos de proteção de plataforma e usá-las como uma proteção personalizada

Conforme mostrado anteriormente, o analisador reconhece os métodos estáticos de proteção de plataforma no tipo OperatingSystem, como OperatingSystem.IsWindows e também RuntimeInformation.IsOSPlatform. No entanto, recomenda-se armazenar em cache o resultado da proteção em um campo e reutilizá-lo ou usar métodos de proteção personalizados para verificar uma plataforma. O analisador precisa reconhecer essas APIs como uma proteção personalizada e não deve gerar avisos sobre as APIs protegidas por elas. Os atributos de proteção foram introduzidos no .NET 6 para dar suporte ao seguinte cenário:

Opcionalmente, esses atributos podem incluir um número de versão. Eles podem ser aplicados várias vezes para proteger mais de uma plataforma e podem ser usados para anotar um campo, uma propriedade ou um método.

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
        }
    }
}

Marcar o site da chamada como específico da plataforma

Os nomes de plataforma devem corresponder à API de chamada dependente da plataforma. Se a cadeia de caracteres da plataforma incluir uma versão:

  • Para o atributo [SupportedOSPlatform("platformVersion")], o version da plataforma do site de chamada deve ser maior ou igual ao Version da plataforma de chamada

  • Para o atributo [UnsupportedOSPlatform("platformVersion")], o version da plataforma do site de chamada deve ser menor ou igual ao Version da plataforma de chamada

    // 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();
    }
    

Declarar o site da chamada com a verificação de plataforma

Todas as verificações condicionais usadas nos exemplos de proteção de plataforma também podem ser usadas como condição para 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
}

Confira também