Condividi tramite


Analizzatore della compatibilità della piattaforma

Probabilmente si è sentito il motto di "One .NET": una singola piattaforma unificata per la creazione di qualsiasi tipo di applicazione. .NET SDK include ASP.NET Core, Entity Framework Core, Windows Form, WPF e ML.NET e aggiungerà il supporto per altre piattaforme nel tempo. .NET 5+ cerca di offrire un'esperienza in cui non è necessario ragionare sulle diverse versioni di .NET, ma non tenta di astrarre completamente il sistema operativo sottostante. Si continuerà a essere in grado di chiamare API specifiche della piattaforma, ad esempio P/Invokes e WinRT.

Tuttavia, l'uso di API specifiche della piattaforma in un componente significa che il codice non funziona più in tutte le piattaforme. È stato necessario un modo per rilevare questo problema in fase di progettazione in modo che gli sviluppatori ottengano la diagnostica quando usano inavvertitamente API specifiche della piattaforma. Per raggiungere questo obiettivo, .NET 5 ha introdotto l'analizzatore della compatibilità della piattaforma e le API complementari per aiutare gli sviluppatori a identificare e usare API specifiche della piattaforma, se appropriato.

Le API complementari includono:

  • SupportedOSPlatformAttribute per annotare le API come specifiche della piattaforma e UnsupportedOSPlatformAttribute annotare le API come non supportate in un determinato sistema operativo. Questi attributi possono facoltativamente includere il numero di versione e sono già stati applicati ad alcune API specifiche della piattaforma nelle librerie .NET principali.
  • Is<Platform>() e Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) metodi statici nella System.OperatingSystem classe per chiamare in modo sicuro API specifiche della piattaforma. Ad esempio, OperatingSystem.IsWindows() può essere usato per proteggere una chiamata a un'API specifica di Windows e OperatingSystem.IsWindowsVersionAtLeast() può essere usato per proteggere una chiamata API specifica di Windows con controllo delle versioni. Guarda questi esempi di come questi metodi possono essere usati come protezioni per riferimenti API specifici della piattaforma.

Prerequisiti

L'analizzatore della compatibilità della piattaforma è uno degli analizzatori della qualità del codice Roslyn. Questi analizzatori sono inclusi in .NET SDK. L'analizzatore di compatibilità della piattaforma è abilitato per impostazione predefinita solo per i progetti che hanno come obiettivo net5.0 o una versione successiva. Tuttavia, è possibile abilitarlo per i progetti destinati ad altri framework.

Come l'analizzatore determina la dipendenza della piattaforma

  • Un'API non con attributi viene considerata funzionante in tutte le piattaforme del sistema operativo.

  • Un'API contrassegnata con [SupportedOSPlatform("platform")] è considerata portabile solo per la piattaforma specificata e per qualsiasi piattaforma di cui è un subset.

    • L'attributo può essere applicato più volte per indicare il supporto di più piattaforme, ad esempio [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Se la piattaforma è un subset di un'altra piattaforma, l'attributo implica che anche la piattaforma superset è supportata. Ad esempio, [SupportedOSPlatform("iOS")] implica che l'API è supportata in iOS e anche nella piattaforma superset, MacCatalyst.
    • L'analizzatore genererà un avviso se si fa riferimento a API specifiche della piattaforma senza un contesto di piattaforma appropriato:
      • Avvisa se il progetto non è destinato alla piattaforma supportata, ad esempio un'API specifica di Windows chiamata da un progetto destinato a iOS <TargetFramework>net5.0-ios14.0</TargetFramework>.
      • Avvisa se il progetto è multipiattaforma e chiama API specifiche della piattaforma, ad esempio un'API specifica di Windows chiamata da TFM <TargetFramework>net5.0</TargetFramework>multipiattaforma.
      • Non avvisa se viene fatto riferimento all'API specifica della piattaforma all'interno di un progetto destinato a una delle piattaforme specificate , ad esempio per un'API specifica di Windows chiamata da finestre <TargetFramework>net5.0-windows</TargetFramework> di destinazione del progetto e la generazione di file AssemblyInfo.cs è abilitata per il progetto.
      • Non avvisa se la chiamata API specifica della piattaforma è protetta dai metodi di controllo della piattaforma corrispondenti ( ad esempio, una chiamata API specifica di Windows sorvegliata da OperatingSystem.IsWindows()).
      • Non avvisa se viene fatto riferimento all'API specifica della piattaforma dallo stesso contesto specifico della piattaforma (anche il sito di chiamata è attribuito con [SupportedOSPlatform("platform")).
  • Un'API contrassegnata con [UnsupportedOSPlatform("platform")] è considerata non supportata nella piattaforma specificata e in tutte le piattaforme che sono un suo subset, ma supportata per tutte le altre piattaforme.

    • L'attributo può essere applicato più volte con piattaforme diverse, [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")]ad esempio .
    • Se la piattaforma è un subset di un'altra piattaforma, l'attributo implica che anche la piattaforma superset non è supportata. Ad esempio, [UnsupportedOSPlatform("iOS")] implica che l'API non è supportata iOS e anche nella piattaforma superset , MacCatalyst.
    • L'analizzatore genera un avviso solo se platform è efficace per il sito di chiamata:
      • Avvisa se il progetto è destinato a una piattaforma considerata non supportata (ad esempio, se l'API è attribuita con [UnsupportedOSPlatform("windows")] e il sito di chiamata è destinato a <TargetFramework>net5.0-windows</TargetFramework>).

      • Avvisa se il progetto è di destinazione multipla e platform viene incluso nel gruppo di elementi MSBuild <SupportedPlatform> predefinito o se platform è incluso manualmente all'interno del MSBuild<gruppo elementi SupportedPlatform> :

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • Non avvisa se si sta creando un'app che non ha come destinazione la piattaforma non supportata o è multi-destinazione e la piattaforma non è inclusa nel gruppo di elementi MSBuild <SupportedPlatform> predefinito.

  • È possibile creare un'istanza di entrambi gli attributi con o senza numeri di versione come parte del nome della piattaforma. I numeri di versione sono nel formato di major.minor[.build[.revision]]; major.minor è obbligatorio e le parti build e revision sono facoltative. Ad esempio, "Windows6.1" indica Windows versione 6.1, ma "Windows" viene interpretato come Windows 0.0.

Per altre informazioni, vedere esempi di funzionamento degli attributi e della diagnostica che causano.

Come l'analizzatore riconosce le piattaforme di destinazione TFM

L'analizzatore non controlla le piattaforme di destinazione del moniker framework di destinazione (TFM) dalle proprietà di MSBuild, ad esempio <TargetFramework> o <TargetFrameworks>. Se tfm ha una piattaforma di destinazione, MSBuild inserisce un SupportedOSPlatform attributo con il nome della piattaforma di destinazione nel file AssemblyInfo.cs , utilizzato dall'analizzatore. Ad esempio, se tfm è net5.0-windows10.0.19041, MSBuild inserisce l'attributo [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] nel file AssemblyInfo.cs e l'intero assembly viene considerato solo Windows. Pertanto, la chiamata di API solo Windows con versione 7.0 o precedente non provocherebbe avvisi nel progetto.

Annotazioni

Se la generazione di file AssemblyInfo.cs è disabilitata per il progetto , ovvero la <GenerateAssemblyInfo> proprietà è impostata su false), l'attributo a livello SupportedOSPlatform di assembly richiesto non può essere aggiunto da MSBuild. In questo caso è possibile che vengano visualizzati avvisi per l'utilizzo di API specifiche della piattaforma anche se la piattaforma specifica è stata impostata come destinazione. Per risolvere gli avvisi, abilitare la generazione del file AssemblyInfo.cs o aggiungere manualmente l'attributo nel progetto.

Inclusione della piattaforma

.NET 6 ha introdotto il concetto di inclusione della piattaforma, in cui una piattaforma può essere un subset di un'altra piattaforma. Un'annotazione per la piattaforma subset implica lo stesso supporto (o la relativa mancanza) per la piattaforma superset. Se un metodo di controllo della piattaforma nel OperatingSystem tipo ha un SupportedOSPlatformGuard("supersetPlatform")] attributo , supersetPlatform viene considerato un superset della piattaforma del sistema operativo controllata dal metodo.

Ad esempio, il OperatingSystem.IsIOS() metodo è con attributi [SupportedOSPlatformGuard("MacCatalyst")]. Di conseguenza, si applicano le istruzioni seguenti:

  • I OperatingSystem.IsIOS() metodi e OperatingSystem.IsIOSVersionAtLeast controllano non solo la iOS piattaforma, ma anche la MacCatalyst piattaforma.
  • [SupportedOSPlatform("iOS")] implica che l'API è supportata in iOS e anche nella piattaforma superset, MacCatalyst. È possibile usare l'attributo [UnsupportedOSPlatform("MacCatalyst")] per escludere questo supporto implicito.
  • [UnsupportedOSPlatform("iOS") implica che l'API non è supportata in iOS e MacCatalyst. È possibile usare l'attributo [SupportedOSPlatform("MacCatalyst")] per escludere questa mancanza implicita di supporto.

Si consideri la matrice di copertura seguente, dove ✔️ indica che la piattaforma è supportata e ❌ indica che la piattaforma non è supportata.

Piattaforma SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
Sottoinsieme ✔️ ✔️
Sovrainsieme ✔️ ✔️ ✔️ ✔️

Suggerimento

Le stesse regole si applicano agli SupportedOSPlatformGuard attributi e UnsupportedOSPlatformGuard .

Il frammento di codice seguente illustra come combinare gli attributi per impostare il livello di supporto corretto.

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

Scenari avanzati per le combinazioni di attributi

  • Se sono presenti una combinazione di [SupportedOSPlatform] attributi e [UnsupportedOSPlatform] , tutti gli attributi vengono raggruppati in base all'identificatore della piattaforma del sistema operativo:

    • Solo elenco supportato. Se la versione più bassa per ogni piattaforma del sistema operativo è un attributo [SupportedOSPlatform], l'API viene considerata supportata solo dalle piattaforme elencate e non supportata da tutte le altre piattaforme. Gli attributi facoltativi [UnsupportedOSPlatform] per ogni piattaforma possono avere solo una versione successiva della versione minima supportata, che indica che l'API viene rimossa a partire dalla versione specificata.

      // 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();
      
    • Elenco solo di elementi non supportati. Se la versione più bassa per ogni piattaforma del sistema operativo è un attributo [UnsupportedOSPlatform], l'API viene considerata non supportata solo dalle piattaforme elencate e supportata da tutte le altre piattaforme. L'elenco potrebbe avere [SupportedOSPlatform] un attributo con la stessa piattaforma, ma una versione successiva, che indica che l'API è supportata a partire da tale versione.

      // 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();
      
    • Elenco di elementi incoerenti. Se la versione più bassa per alcune piattaforme è [SupportedOSPlatform] mentre è [UnsupportedOSPlatform] per altre piattaforme, viene considerata incoerente, che non è supportata per l'analizzatore. Se si verifica un'incoerenza, l'analizzatore ignora le [UnsupportedOSPlatform] piattaforme.

      • Se le versioni più basse degli attributi [SupportedOSPlatform] e [UnsupportedOSPlatform] sono uguali, l'analizzatore considera la piattaforma come parte dell'elenco Supportato solo.
  • Gli attributi della piattaforma possono essere applicati a tipi, membri (metodi, campi, proprietà ed eventi) e assembly con nomi o versioni diverse della piattaforma.

    • Gli attributi applicati al livello target superiore influiscono su tutti i relativi membri e tipi.
    • Gli attributi a livello di sotto-elemento si applicano solo se rispettano la regola "le annotazioni dei sotto-elementi possono restringere il supporto delle piattaforme, ma non possono estenderlo".
      • Quando l'elemento padre ha l'elenco Solo supportato , gli attributi dei membri figlio non possono aggiungere un nuovo supporto per la piattaforma, in quanto estenderebbe il supporto padre. Il supporto per una nuova piattaforma può essere aggiunto solo al nodo padre. Tuttavia, l'elemento figlio può avere l'attributo Supported nelle versioni successive per la stessa piattaforma, poiché ciò restringe il supporto. Inoltre, l'elemento figlio può avere l'attributo Unsupported con la stessa piattaforma poiché restringe anche il supporto padre.
      • Quando l'elenco padre è supportato solamente per le piattaforme non supportate, gli attributi dei membri figlio possono aggiungere supporto per una nuova piattaforma, poiché questo riduce il supporto del padre. Ma non può avere l'attributo Supported per la stessa piattaforma dell'elemento padre, perché ciò estenderebbe il supporto di quest'ultimo. Il supporto per la stessa piattaforma può essere aggiunto solo all'elemento padre in cui è stato applicato l'attributo originale Unsupported .
    • Se [SupportedOSPlatform("platformVersion")] viene applicato più volte per un'API con lo stesso platform nome, l'analizzatore considera solo quello con la versione minima.
    • Se [UnsupportedOSPlatform("platformVersion")] viene applicato più di due volte per un'API con lo stesso platform nome, l'analizzatore considera solo i due con le versioni meno recenti.

    Annotazioni

    Un'API supportata inizialmente ma non supportata (rimossa) in una versione successiva non dovrebbe essere supportata nuovamente in una versione ancora successiva.

Esempi di funzionamento degli attributi e della diagnostica che producono

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

Gestire gli avvisi segnalati

Il modo consigliato per gestire questa diagnostica consiste nell'assicurarsi di chiamare solo API specifiche della piattaforma durante l'esecuzione su una piattaforma appropriata. Di seguito sono riportate le opzioni che è possibile usare per risolvere gli avvisi; scegliere quale sia la scelta più appropriata per la situazione:

  • Guardi la chiamata. A tale scopo, è possibile chiamare in modo condizionale il codice in fase di esecuzione. Verificare se si sta eseguendo sulla piattaforma desiderata Platform utilizzando uno dei metodi di verifica della piattaforma, ad esempio OperatingSystem.Is<Platform>() o OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0). Esempio.

  • Contrassegnare il punto di chiamata come specifico della piattaforma. È anche possibile scegliere di contrassegnare le PROPRIE API come specifiche della piattaforma, in modo da inoltrare in modo efficace i requisiti ai chiamanti. Contrassegnare il metodo o l'intero assembly contenente gli stessi attributi della chiamata dipendente dalla piattaforma a cui si fa riferimento. Esempi.

  • Asserire il punto di chiamata con il controllo della piattaforma. Se non si vuole un sovraccarico dovuto a un'istruzione aggiuntiva if durante l'esecuzione, usare Debug.Assert(Boolean). Esempio.

  • Eliminare il codice. In genere non ciò che vuoi perché significa perdere fedeltà quando il codice viene usato dagli utenti di Windows. Per i casi in cui esiste un'alternativa multipiattaforma, è probabile che sia preferibile usare questa opzione anziché API specifiche della piattaforma.

  • Eliminare l'avviso. È anche possibile eliminare semplicemente l'avviso, tramite una voce EditorConfig o #pragma warning disable CA1416. Tuttavia, questa opzione deve essere un'ultima risorsa quando si usano API specifiche della piattaforma.

    Suggerimento

    Quando si disabilitano gli avvisi usando le #pragma direttive del pre-compilatore, gli identificatori di destinazione sono case-sensitive. Ad esempio, ca1416 non disabiliterebbe effettivamente l'avviso CA1416.

Proteggere LE API specifiche della piattaforma con metodi di protezione

Il nome della piattaforma del metodo guard deve corrispondere al nome della piattaforma API dipendente dalla piattaforma chiamante. Se la stringa della piattaforma dell'API chiamante include la versione:

  • Per l'attributo [SupportedOSPlatform("platformVersion")], la piattaforma del metodo guard version deve essere maggiore o uguale alla piattaforma chiamante Version.

  • Per l'attributo [UnsupportedOSPlatform("platformVersion")] , la piattaforma version del metodo guard deve essere minore o uguale a quella della Versionpiattaforma chiamante.

    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 è necessario proteggere il codice destinato netstandard o netcoreapp in cui non sono disponibili nuove OperatingSystem API, l'API RuntimeInformation.IsOSPlatform può essere usata e rispettata dall'analizzatore. Ma non è ottimizzato come le nuove API aggiunte in OperatingSystem. Se la piattaforma non è supportata nello OSPlatform struct, è possibile chiamare OSPlatform.Create(String) e passare il nome della piattaforma, che l'analizzatore rispetta anche.

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

Annotare le API con attributi di protezione della piattaforma e usarle come protezione personalizzata

Come illustrato in precedenza, l'analizzatore riconosce i metodi statici di platform-guard nel OperatingSystem tipo , ad esempio OperatingSystem.IsWindowse anche RuntimeInformation.IsOSPlatform. Tuttavia, è possibile memorizzare nella cache il risultato della protezione in un campo e riutilizzarlo oppure usare metodi di protezione personalizzati per controllare una piattaforma. L'analizzatore deve riconoscere tali API come protezione personalizzata e non deve avvisare per le API protette da tali API. Gli attributi di protezione sono stati introdotti in .NET 6 per supportare questo scenario:

  • SupportedOSPlatformGuardAttribute annota le API che possono essere usate come protezione per le API annotate con SupportedOSPlatformAttribute.
  • UnsupportedOSPlatformGuardAttribute annota le API che possono essere usate come protezione per le API annotate con UnsupportedOSPlatformAttribute.

Questi attributi possono facoltativamente includere un numero di versione. Possono essere applicati più volte per proteggere più di una piattaforma e possono essere usati per annotare un campo, una proprietà o un metodo.

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

Contrassegnare il sito di chiamata come specifico della piattaforma

I nomi della piattaforma devono corrispondere all'API dipendente dalla piattaforma chiamante. Se la stringa della piattaforma include una versione:

  • Per l'attributo [SupportedOSPlatform("platformVersion")] , la piattaforma version del sito di chiamata deve essere maggiore o uguale alla piattaforma chiamante Version

  • Per l'attributo [UnsupportedOSPlatform("platformVersion")] , la piattaforma version del sito di chiamata deve essere minore o uguale alla piattaforma chiamante 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();
    }
    

Assert the call-site with platform check (Asserzione del sito di chiamata con verifica della piattaforma)

Tutti i controlli condizionali usati negli esempi di platform guard possono essere usati anche come condizione per 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
}

Vedere anche