Analizador de compatibilidad de plataformas

Probablemente ha oído hablar del lema de "One .NET": una única plataforma unificada para crear cualquier tipo de aplicación. El SDK de .NET 5 incluye ASP.NET Core, Entity Framework Core, WinForms, WPF, Xamarin y ML.NET, y agregará compatibilidad con más plataformas con el tiempo. .NET 5 se esfuerza por proporcionar una experiencia en la que no tenga que preocuparse de los distintos tipos de .NET, pero no intenta abstraer completamente el sistema operativo (SO) subyacente. Podrá seguir llamando a las API específicas de la plataforma, por ejemplo, P/Invokes, WinRT o los enlaces de Xamarin para iOS y Android.

Pero el uso de API específicas de la plataforma en un componente significa que el código deje de funcionar en todas las plataformas. Necesitábamos una manera de detectar esto en tiempo de diseño para que los desarrolladores obtuvieran diagnósticos al utilizar accidentalmente API específicas de la plataforma. Para lograr este objetivo, .NET 5 introduce el analizador de compatibilidad de plataforma y API complementarias para ayudar a los desarrolladores a identificar y usar las API específicas de la plataforma cuando sea necesario.

Entre las nuevas API se incluyen:

  • SupportedOSPlatformAttribute para anotar las API como específicas de la plataforma y UnsupportedOSPlatformAttribute para anotar las API como no compatibles en un sistema operativo determinado. Estos atributos pueden incluir opcionalmente el número de versión y ya se han aplicado a algunas API específicas de la plataforma en las bibliotecas .NET básicas.
  • Los métodos estáticos Is<Platform>() y Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) en la clase System.OperatingSystem para llamar a API específicas de la plataforma de forma segura. Por ejemplo, se puede usar OperatingSystem.IsWindows() para proteger una llamada a una API específica de Windows y se puede usar OperatingSystem.IsWindowsVersionAtLeast() para proteger una llamada API específica de Windows con control de versiones. Consulte estos ejemplos sobre cómo se pueden usar estos métodos como protecciones de las referencias de API específicas de la plataforma.

Requisitos previos

El analizador de compatibilidad de plataformas es uno de los analizadores de calidad de código de Roslyn. A partir de .NET 5, estos analizadores se incluyen con el SDK de .NET. El analizador de compatibilidad de plataformas está habilitado de forma predeterminada solo para los proyectos que tienen como destino net5.0 o una versión posterior. Pero puede habilitarlo para proyectos destinados a otros marcos.

Cómo determina el analizador la dependencia de plataformas

  • Una API sin atributos se considera que funciona en todas las plataformas de sistema operativo.

  • Una API marcada con [SupportedOSPlatform("platform")] se considera solo portable a la plataforma especificada y cualquier plataforma de la que sea un subconjunto.

    • El atributo se puede aplicar varias veces para indicar la compatibilidad con varias plataformas, por ejemplo, [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Si la plataforma es un subconjunto de otra plataforma, el atributo implica que también se admite la plataforma de superconjunto. Por ejemplo, [SupportedOSPlatform("iOS")] implica que la API se admite en iOS y también en su plataforma de superconjunto, MacCatalyst.
    • El analizador generará una advertencia si se hace referencia a las API específicas de la plataforma sin un contexto de plataforma adecuado:
      • Genera una advertencia si el proyecto no tiene como destino la plataforma admitida (por ejemplo, una API específica de Windows llamada desde un proyecto dirigido a iOS <TargetFramework>net5.0-ios14.0</TargetFramework>).
      • Genera una advertencia si el proyecto es multiplataforma y llama a API específicas de la plataforma (por ejemplo, una API específica de Windows llamada desde TFM multiplataforma <TargetFramework>net5.0</TargetFramework>).
      • No genera una advertencia si se hace referencia a la API específica de la plataforma dentro de un proyecto que tiene como destino cualquiera de las plataformas especificadas (por ejemplo, para una API específica de Windows llamada desde un proyecto dirigido a Windows <TargetFramework>net5.0-windows</TargetFramework> y la generación de archivos AssemblyInfo.cs está habilitada para el proyecto).
      • No genera una advertencia si la llamada API específica de la plataforma está protegida por los métodos de comprobación de plataforma correspondientes (por ejemplo, una llamada de API específica de Windows protegida por OperatingSystem.IsWindows()).
      • No advierte si se hace referencia a la API específica de la plataforma desde el mismo contexto específico de la plataforma (el sitio de llamada también tiene un atributo con [SupportedOSPlatform("platform")).
  • Una API marcada con [UnsupportedOSPlatform("platform")] se considera no compatible en la plataforma especificada y cualquier plataforma de la que sea un subconjunto, pero compatible con todas las demás plataformas.

    • El atributo se puede aplicar varias veces con diferentes plataformas, por ejemplo, [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")].
    • Si la plataforma es un subconjunto de otra plataforma, el atributo implica que tampoco se admite la plataforma de superconjunto. Por ejemplo, [UnsupportedOSPlatform("iOS")] implica que la API no se admite en iOS ni tampoco en su plataforma de superconjunto, MacCatalyst.
    • El analizador genera una advertencia solo si la platform es efectiva para el sitio de llamada:
      • Advierte si el proyecto tiene como destino la plataforma que se atribuye como no compatible (por ejemplo, si la API tiene el atributo [UnsupportedOSPlatform("windows")] y el sitio de llamada tiene como destino <TargetFramework>net5.0-windows</TargetFramework>).

      • Genera una advertencia si el proyecto tiene varios destinos y platform está incluido en el grupo de elementos predeterminado de MSBuild <SupportedPlatform> o platform se incluye manualmente en el grupo de elementos MSBuild<SupportedPlatform>:

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • No advierte si está creando una aplicación que no tiene como destino la plataforma no compatible o que tiene varios destinos, y la plataforma no se incluye en el grupo de elementos predeterminados de MSBuild <SupportedPlatform>.

  • Se puede crear una instancia de ambos atributos con o sin números de versión como parte del nombre de la plataforma. Los números de versión están en el formato de major.minor[.build[.revision]]; major.minor es obligatorio y las partes build y revision son opcionales. Por ejemplo, "Windows 6.1" indica la versión 6.1 de Windows, pero "Windows" se interpreta como Windows 0.0.

Para más información, consulte los ejemplos de cómo funcionan los atributos y qué diagnósticos causan.

Cómo reconoce el analizador las plataformas de destino de TFM

El analizador no comprueba las plataformas de destino del moniker de la plataforma de destino (TFM) desde las propiedades de MSBuild, como <TargetFramework> o <TargetFrameworks>. Si el TFM tiene una plataforma de destino, MSBuild inserta un atributo SupportedOSPlatform con el nombre de la plataforma de destino en el archivo AssemblyInfo.cs, que el analizador consume. Por ejemplo, si el TFM es net5.0-windows10.0.19041, MSBuild inserta el atributo [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] en el archivo AssemblyInfo.cs y se considera que todo el ensamblado es solo para Windows. Por tanto, la llamada a las API exclusivas de Windows con la versión 7.0 o inferior no provocaría ninguna advertencia en el proyecto.

Nota

Si la generación de archivos AssemblyInfo.cs está deshabilitada para el proyecto (es decir, la propiedad <GenerateAssemblyInfo> está establecida en false), MSBuild no puede agregar el atributo SupportedOSPlatform de nivel de ensamblado necesario. En este caso, podría ver advertencias sobre el uso de API específicas de la plataforma, aunque tenga como destino esa plataforma. Para resolver las advertencias, habilite la generación de archivos AssemblyInfo.cs o agregue el atributo manualmente en el proyecto.

Inclusión de la plataforma

.NET 6 presenta el concepto de inclusión de la plataforma, donde una plataforma puede ser un subconjunto de otra. Una anotación para la plataforma de subconjunto implica la misma compatibilidad (o falta de ella) con la plataforma de superconjunto. Si un método de comprobación de la plataforma del tipo OperatingSystem tiene un atributo SupportedOSPlatformGuard("supersetPlatform")], supersetPlatform se considera un superconjunto de la plataforma del sistema operativo que el método comprueba.

Por ejemplo, al método OperatingSystem.IsIOS() se le atribuye [SupportedOSPlatformGuard("MacCatalyst")]. Por lo tanto, se aplican las siguientes instrucciones:

  • Los métodos OperatingSystem.IsIOS() y OperatingSystem.IsIOSVersionAtLeast comprueban no solo la plataforma iOS, sino también la plataforma MacCatalyst.
  • [SupportedOSPlatform("iOS")] implica que la API se admite en iOS y también en su plataforma de superconjunto, MacCatalyst. Puede usar el atributo [UnsupportedOSPlatform("MacCatalyst")] para excluir esta compatibilidad implícita.
  • [UnsupportedOSPlatform("iOS") implica que la API no se admite en iOS ni en MacCatalyst. Puede usar el atributo [SupportedOSPlatform("MacCatalyst")] para excluir esta falta de compatibilidad implícita.

Tenga en cuenta la siguiente matriz de cobertura, donde ✔️ indica que se admite la plataforma y ❌ indica que no se admite.

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

Sugerencia

Se aplican las mismas reglas para los atributos SupportedOSPlatformGuard y UnsupportedOSPlatformGuard.

En el siguiente fragmento de código se muestra cómo puede combinar atributos para establecer el nivel correcto de compatibilidad.

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

Escenarios avanzados para combinaciones de atributos

  • Si hay una combinación de los atributos [SupportedOSPlatform] y [UnsupportedOSPlatform], todos los atributos se agrupan por identificador de plataforma de sistema operativo:

    • Lista Solo compatibles. Si la versión más antigua de cada plataforma de sistema operativo es un atributo [SupportedOSPlatform], se considera que la API solo es compatible con las plataformas de la lista y no es compatible con todas las demás plataformas. Los atributos de [UnsupportedOSPlatform] opcionales para cada plataforma solo pueden tener una versión más alta de la versión mínima admitida, lo que indica que la API se ha quitado a partir de la versión 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 Solo no compatibles Si la versión más antigua de cada plataforma de sistema operativo es un atributo [UnsupportedOSPlatform], se considera que la API no es compatible solo con las plataformas de la lista y es compatible con todas las demás plataformas. La lista podría tener el atributo [SupportedOSPlatform] con la misma plataforma pero con una versión superior, lo que indica que la API se admite a partir de esa versión.

      // 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 incoherentes: Si la versión más baja para algunas plataformas es [SupportedOSPlatform] y [UnsupportedOSPlatform] lo es para otras, se considera incoherente, lo que el analizador no admite. Si se produce una incoherencia, el analizador omite las plataformas [UnsupportedOSPlatform].

      • Si las versiones más bajas de los atributos [SupportedOSPlatform] y [UnsupportedOSPlatform] son iguales, el analizador considera la plataforma como parte de la lista Solo compatibles.
  • Los atributos de plataforma se pueden aplicar a tipos, miembros (métodos, campos, propiedades y eventos) y ensamblados con otros nombres o versiones de plataforma.

    • Los atributos aplicados en el target de nivel superior afectan a todos sus miembros y tipos.
    • Solo se aplican los atributos de nivel secundario si se adhieren a la regla de "las anotaciones secundarias pueden limitar la compatibilidad de plataformas, pero no pueden ampliarla".
      • Cuando el elemento primario tiene la lista Solo compatibles, los atributos de los miembros secundarios no pueden agregar una nueva compatibilidad con la plataforma, ya que eso extendería la compatibilidad con el elemento primario. La compatibilidad con una nueva plataforma solo se puede agregar al propio elemento primario. Pero el elemento secundario puede tener el atributo Supported para la misma plataforma con versiones posteriores, ya que eso limita la compatibilidad. Además, el elemento secundario puede tener el atributo Unsupported con la misma plataforma, lo que también limita la compatibilidad con el elemento primario.
      • Cuando el elemento primario tiene la lista Solo no compatibles, los atributos de los miembros secundarios no pueden agregar compatibilidad con una plataforma nueva, ya que eso limitaría la compatibilidad con el elemento primario. Pero no puede tener el atributo Supported para la misma plataforma que el elemento primario, porque eso amplía la compatibilidad con el elemento primario. La compatibilidad con la misma plataforma solo se puede agregar al elemento primario en el que se ha aplicado el atributo Unsupported original.
    • Si se aplica [SupportedOSPlatform("platformVersion")] más de una vez para una API con el mismo nombre de platform, el analizador solo tiene en cuenta la que tiene la versión mínima.
    • Si se aplica [UnsupportedOSPlatform("platformVersion")] más de dos veces para una API con el mismo nombre de platform, el analizador solo tiene en cuenta las dos con las versiones más anteriores.

    Nota

    No se espera que una API admitida inicialmente pero no admitida (retirada) en una versión posterior pueda volver a admitirse en una versión aún más tardía.

Ejemplos de cómo funcionan los atributos y qué diagnóstico producen

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

Control de advertencias detectadas

La manera recomendada de tratar estos diagnósticos es asegurarse de que solo se llama a las API específicas de la plataforma cuando se ejecuta en una plataforma adecuada. A continuación se muestran las opciones que puede usar para solucionar las advertencias; elija lo que sea más adecuado para su situación:

  • Proteja la llamada. Para ello, puede llamar condicionalmente al código en tiempo de ejecución. Compruebe si se ejecuta en una Platform deseada mediante uno de los métodos de comprobación de plataforma, por ejemplo, OperatingSystem.Is<Platform>() u OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0). Ejemplo.

  • Marque el sitio de llamada como específico de la plataforma. También puede elegir marcar sus propias API como específicas de la plataforma y, por tanto, reenviar los requisitos a los autores de llamadas de forma eficaz. Marque el método o tipo contenedor o todo el ensamblado con los mismos atributos que la llamada dependiente de la plataforma a la que se hace referencia. Ejemplos.

  • Aserción del sitio de llamada con comprobación de la plataforma. O bien, si no quiere sobrecargar una instrucción if adicional en tiempo de ejecución, llame a Debug.Assert(Boolean) en su lugar: Ejemplo.

  • Elimine el código. Por lo general, no lo que desea porque significa que perderá fidelidad cuando los usuarios de Windows usen el código. En los casos en los que existe una alternativa multiplataforma, es probable que sea mejor usarla que las API específicas de la plataforma.

  • Suprima la advertencia. También puede suprimir la advertencia, ya sea mediante una entrada EditorConfig o #pragma warning disable CA1416. Sin embargo, esta opción debe ser el último recurso cuando se usan API específicas de la plataforma.

    Sugerencia

    Al deshabilitar las advertencias mediante las directivas del precompilador #pragma, los identificadores de destino distinguen mayúsculas de minúsculas. Por ejemplo, ca1416 no deshabilitaría realmente la advertencia CA1416.

Restricción de API específicas de la plataforma con métodos de restricción

El nombre de la plataforma del método de restricción debe coincidir con el nombre de la plataforma de API dependiente de la plataforma que llama. Si la cadena de la plataforma de la API de llamada incluye la versión:

  • En el caso del atributo [SupportedOSPlatform("platformVersion")], la version de la plataforma del método de restricción debe ser mayor o igual que la Version de la plataforma que realiza la llamada.

  • En el caso del atributo [UnsupportedOSPlatform("platformVersion")], la version de la plataforma del método de restricción debe ser menor o igual que la Version de la plataforma que realiza la llamada.

    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
        }
    }
    
  • Si necesita restringir código destinado a netstandard o netcoreapp, donde las nuevas API OperatingSystem no están disponibles, se puede usar la API RuntimeInformation.IsOSPlatform, que el analizador respetará. Pero no es tan optimizado como las nuevas API agregadas en OperatingSystem. Si la plataforma no se admite en la estructura OSPlatform, puede llamar a OSPlatform.Create(String) y pasar el nombre de la plataforma, que el analizador también respeta.

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

Anotación de API con atributos de protección de la plataforma y su uso como protección personalizada

Como se ha mostrado anteriormente, el analizador reconoce los métodos estáticos de protección de la plataforma en el tipo OperatingSystem, como OperatingSystem.IsWindows, y también RuntimeInformation.IsOSPlatform. Sin embargo, es posible que quiera almacenar en caché el resultado de la protección en un campo y reutilizarlo, o bien usar métodos de protección personalizados para comprobar una plataforma. El analizador debe reconocer estas API como una protección personalizada y no debe avisar a las API protegidas por ellas. Los atributos de protección se introdujeron en .NET 6 para admitir este escenario:

Estos atributos pueden incluir opcionalmente un número de versión. Se pueden aplicar varias veces para proteger más de una plataforma y se pueden usar para anotar un campo, una propiedad o un 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
        }
    }
}

Marcado del sitio de llamada como específico de la plataforma

Los nombres de la plataforma deben coincidir con la API dependiente de la plataforma que realiza la llamada. Si la cadena de la plataforma incluye una versión:

  • En el caso del atributo [SupportedOSPlatform("platformVersion")], la version de la plataforma del sitio de llamada debe ser mayor o igual que la Version de la plataforma que realiza la llamada.

  • En el caso del atributo [UnsupportedOSPlatform("platformVersion")], la version de la plataforma del sitio de llamada debe ser menor o igual que la Version de la plataforma que realiza la llamada.

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

Aserción del sitio de llamada con comprobación de la plataforma

Todas las comprobaciones condicionales que se usan en los ejemplos de restricción de la plataforma también se pueden usar como condición 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 también