Analisador de compatibilidade de plataforma

Você provavelmente já ouviu o lema de "One .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 .NET 5 se esforça para fornecer uma experiência em que você não precisa raciocinar sobre os diferentes tipos do .NET, mas não tenta abstrair totalmente o sistema operacional (SO) subjacente. Você continuará a poder chamar APIs específicas da plataforma, por exemplo, P/Invokes, WinRT ou as associações Xamarin para iOS e Android.

Mas usar APIs específicas da plataforma em um componente significa que o código não funciona mais em todas as plataformas. Precisávamos de uma maneira de detetar isso em tempo de design para que os desenvolvedores obtenham diagnósticos quando usam inadvertidamente APIs específicas da plataforma. Para atingir esse objetivo, o .NET 5 apresenta o analisador de compatibilidade de plataforma e APIs complementares para ajudar os desenvolvedores a identificar e usar APIs específicas da plataforma quando apropriado.

As novas APIs incluem:

  • SupportedOSPlatformAttribute para anotar APIs como sendo específicas da plataforma e UnsupportedOSPlatformAttribute para anotar APIs como não sendo suportadas em um sistema operacional específico. Esses atributos podem, opcionalmente, incluir o número da versão e já foram aplicados a algumas APIs específicas da plataforma nas bibliotecas principais do .NET.
  • Is<Platform>() e Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) métodos estáticos na classe para chamar APIs específicas da System.OperatingSystem 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 de como esses métodos podem ser usados como protetores de referências de API específicas da 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 apenas para projetos de destino net5.0 ou uma versão posterior. No entanto, você pode habilitá-lo para projetos destinados a outras estruturas.

Como o analisador determina a dependência da plataforma

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

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

    • O atributo pode ser aplicado várias vezes para indicar suporte a várias plataformas, por exemplo [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Se a plataforma for um subconjunto de outra plataforma, o atributo implica que a plataforma de superconjunto também é suportada. Por exemplo, [SupportedOSPlatform("iOS")] implica que a API é suportada em iOS e também em sua plataforma superset, MacCatalyst.
    • O analisador produzirá um aviso se APIs específicas da plataforma forem referenciadas sem um contexto de plataforma adequado:
      • Avisa se o projeto não se destina à plataforma suportada (por exemplo, uma API específica do Windows chamada a partir de um projeto destinado ao iOS <TargetFramework>net5.0-ios14.0</TargetFramework>).
      • Avisa se o projeto é multiplataforma e chama APIs específicas da plataforma (por exemplo, uma API específica do Windows chamada de TFM <TargetFramework>net5.0</TargetFramework>multiplataforma).
      • Não avisa se a API específica da plataforma é referenciada dentro de um projeto destinado a qualquer uma das plataformas especificadas (por exemplo, para uma API específica do Windows chamada a partir de um projeto de janelas <TargetFramework>net5.0-windows</TargetFramework> de destino e a geração de arquivos AssemblyInfo.cs está habilitada para o projeto).
      • Não avisa se a chamada de API específica da 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 da plataforma é referenciada a partir do mesmo contexto específico da plataforma (site de chamada também atribuído com [SupportedOSPlatform("platform")).
  • Uma API marcada com [UnsupportedOSPlatform("platform")] é considerada sem suporte na plataforma especificada e em qualquer plataforma da qual seja um subconjunto, mas suportada para todas as outras plataformas.

    • O atributo pode ser aplicado várias vezes com diferentes plataformas, por exemplo, [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")].
    • Se a plataforma for um subconjunto de outra plataforma, o atributo implica que a plataforma de superconjunto também não é suportada. Por exemplo, [UnsupportedOSPlatform("iOS")] implica que a API não é suportada em iOS e também em sua plataforma superset, MacCatalyst.
    • O analisador produz um aviso somente se o platform for eficaz para o local de chamada:
      • Avisa se o projeto tem como alvo a plataforma atribuída como não suportada (por exemplo, se a API é atribuída e [UnsupportedOSPlatform("windows")] os destinos <TargetFramework>net5.0-windows</TargetFramework>do site de chamada).

      • Avisa se o projeto é multi-target e o platform está incluído no grupo de itens padrão do MSBuild<SupportedPlatform>, ou o platform está incluído manualmente no MSBuild<grupo de itens SupportedPlatform>:

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

  • Ambos os atributos podem ser instanciados com ou sem números de versão como parte do nome da plataforma. Os números de versão estão no formato de major.minor[.build[.revision]]; major.minor é obrigatório e as revisionbuild e partes são opcionais. Por exemplo, "Windows6.1" indica Windows versão 6.1, mas "Windows" é interpretado como Windows 0.0.

Para obter mais informações, consulte exemplos de como os atributos funcionam e quais diagnósticos eles causam.

Como o analisador reconhece as plataformas de destino do TFM

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

Nota

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

Inclusão na plataforma

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

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

  • Os OperatingSystem.IsIOS() métodos e OperatingSystem.IsIOSVersionAtLeast verificam não só a iOS plataforma, mas também a MacCatalyst plataforma.
  • [SupportedOSPlatform("iOS")] implica que a API é suportada na iOS e também na sua plataforma superset, MacCatalyst. Você pode usar o [UnsupportedOSPlatform("MacCatalyst")] atributo para excluir esse suporte implícito.
  • [UnsupportedOSPlatform("iOS") implica que a API não é suportada em iOS e MacCatalyst. Você pode usar o [SupportedOSPlatform("MacCatalyst")] atributo para excluir essa falta implícita de suporte.

Considere a seguinte matriz de cobertura, onde ✔️ indica que a plataforma é suportada e ❌ indica que a plataforma não é suportada.

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

Gorjeta

As mesmas regras se aplicam para os SupportedOSPlatformGuard e UnsupportedOSPlatformGuard atributos.

O trecho de código a seguir mostra como você pode combinar atributos para definir o nível certo de suporte.

  // 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 para combinações de atributos

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

    • Lista apenas suportada. Se a versão mais baixa para cada plataforma de sistema operacional for um [SupportedOSPlatform] atributo, a API será considerada suportada apenas pelas plataformas listadas e não suportada por todas as outras plataformas. Os atributos opcionais [UnsupportedOSPlatform] para cada plataforma só podem ter uma versão superior da versão mínima suportada, o que indica 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 apenas sem suporte. Se a versão mais baixa para cada plataforma de sistema operacional for um [UnsupportedOSPlatform] atributo, a API será considerada como não suportada apenas pelas plataformas listadas e suportada por todas as outras plataformas. A lista pode ter [SupportedOSPlatform] atributo com a mesma plataforma, mas uma versão superior, o que indica que a API é suportada 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 inconsistente. Se a versão mais baixa para algumas plataformas é [SupportedOSPlatform] enquanto é [UnsupportedOSPlatform] para outras plataformas, é considerado inconsistente, o que não é suportado para o analisador. Se ocorrer inconsistência, o analisador ignora as [UnsupportedOSPlatform] plataformas.

      • Se as versões mais baixas de [SupportedOSPlatform] e [UnsupportedOSPlatform] atributos forem iguais, o analisador considerará a plataforma como parte da lista Somente suportado.
  • Os atributos da 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 no nível target superior afetam todos os seus membros e tipos.
    • Os atributos de nível filho só se aplicam se aderirem à regra "as anotações filho podem restringir o suporte às plataformas, mas não podem ampliá-lo".
      • Quando o pai tem a lista Somente suportado , os atributos de membro filho não podem adicionar um novo suporte à plataforma, pois isso seria estender o suporte pai. O suporte para uma nova plataforma só pode ser adicionado ao próprio pai. Mas a criança pode ter o Supported atributo para a mesma plataforma com versões posteriores, pois isso estreita o suporte. Além disso, a criança pode ter o Unsupported atributo com a mesma plataforma, pois isso também estreita o suporte dos pais.
      • Quando o pai tem a lista Somente sem suporte, os atributos de membro filho podem adicionar suporte para uma nova plataforma, pois isso reduz o suporte pai. Mas não pode ter o atributo para a mesma plataforma que o pai, porque isso estende o Supported suporte pai. O suporte para a mesma plataforma só pode ser adicionado ao pai onde o atributo original Unsupported foi aplicado.
    • Se [SupportedOSPlatform("platformVersion")] for aplicado mais de uma vez para uma API com o mesmo platform nome, o analisador só considera aquela com a versão mínima.
    • Se [UnsupportedOSPlatform("platformVersion")] for aplicado mais de duas vezes para uma API com o mesmo platform nome, o analisador só considera as duas com as versões mais antigas.

    Nota

    Não se espera que uma API que foi suportada inicialmente, mas não suportada (removida) em uma versão posterior, seja resuportada em uma versão ainda mais tardia.

Exemplos de como os atributos funcionam e que 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 você chame apenas APIs específicas da plataforma quando executado em uma plataforma apropriada. A seguir estão as opções que você pode usar para abordar os avisos; Escolha o que for mais adequado para a sua situação:

  • Guarde a chamada. Você pode conseguir isso chamando condicionalmente o código em tempo de execução. Verifique se você está executando em um desejado Platform 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 de chamada como específico da plataforma. Você também pode optar por marcar suas próprias APIs como sendo específicas da plataforma, assim, efetivamente apenas encaminhando os requisitos para seus chamadores. Marque o método ou tipo de contenção ou o assembly inteiro com os mesmos atributos da chamada dependente de plataforma referenciada. Exemplos.

  • Asserte o site de chamada com a verificação da plataforma. Se você não quiser a sobrecarga de uma instrução adicional if em tempo de execução, use Debug.Assert(Boolean). Exemplo.

  • Exclua o código. Geralmente não é o que você quer, porque isso significa que você perde a fidelidade quando seu código é usado por usuários do Windows. Para os casos em que existe uma alternativa entre plataformas, provavelmente é melhor usá-la em relação a APIs específicas da plataforma.

  • Suprima o aviso. Você também pode simplesmente suprimir o aviso, através de uma entrada EditorConfig ou #pragma warning disable CA1416. No entanto, essa opção deve ser um último recurso ao usar APIs específicas da plataforma.

    Gorjeta

    Ao desabilitar avisos usando as #pragma diretivas pré-compilador, os identificadores que você está segmentando diferenciam maiúsculas de minúsculas. Por exemplo, ca1416 não desativaria o aviso CA1416.

APIs específicas da plataforma Guard com métodos de proteção

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

  • Para o [SupportedOSPlatform("platformVersion")] atributo, a plataforma do método guard deve ser maior ou igual à plataforma versionVersionde chamada .

  • Para o [UnsupportedOSPlatform("platformVersion")] atributo, a plataforma do método guard deve ser menor ou igual à plataforma versionVersionde 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 que tem como alvo netstandard ou onde novas OperatingSystem APIs não estão disponíveis, a RuntimeInformation.IsOSPlatform API pode ser usada e será respeitada netcoreapp pelo analisador. Mas não é tão otimizado quanto as novas APIs adicionadas no OperatingSystem. Se a plataforma não for suportada OSPlatform no struct, você pode chamar OSPlatform.Create(String) e passar o nome da plataforma, que o analisador também respeita.

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

Anote APIs com atributos de proteção de plataforma e use-a como uma proteção personalizada

Como mostrado anteriormente, o analisador reconhece os métodos estáticos de proteção de OperatingSystem plataforma no tipo, como OperatingSystem.IsWindows, e também RuntimeInformation.IsOSPlatform. No entanto, você pode querer armazenar em cache o resultado da guarda em um campo e reutilizá-lo, ou usar métodos de guarda personalizados para verificar uma plataforma. O analisador precisa reconhecer essas APIs como um protetor personalizado e não deve avisar sobre as APIs protegidas por elas. Os atributos guard foram introduzidos no .NET 6 para suportar este cenário:

Esses atributos podem, opcionalmente, 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, propriedade ou 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 site de chamada como específico da plataforma

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

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

  • Para o [UnsupportedOSPlatform("platformVersion")] atributo, a plataforma do site de chamada deve ser menor ou igual à plataforma version de chamada 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();
    }
    

Afirmar o site de chamada com verificação de plataforma

Todas as verificações condicionais usadas nos exemplos de guarda 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
}

Consulte também