Analizzatore della compatibilità della piattaforma
È probabile che si conosca il motto "One .NET": una singola piattaforma unificata per la creazione di qualsiasi tipo di applicazione. .NET 5 SDK include ASP.NET Core, Entity Framework Core, WinForms, WPF, Xamarin e ML.NET e aggiungerà il supporto per altre piattaforme nel tempo. .NET 5 si impegna a offrire un'esperienza in cui non è necessario pensare alle diverse versioni di .NET, ma senza astrarre completamente il sistema operativo sottostante. Continuerà a essere possibile chiamare API specifiche della piattaforma, ad esempio P/Invokes, WinRT o le associazioni Xamarin per iOS e Android.
L'uso di API specifiche della piattaforma in un componente significa tuttavia che il codice non funziona più in tutte le piattaforme. Era necessario trovare un modo per rilevare questo problema in fase di progettazione in modo che gli sviluppatori potessero ottenere dati di diagnostica quando usano inavvertitamente API specifiche della piattaforma. Per raggiungere questo obiettivo, .NET 5 introduce 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 nuove API includono:
- SupportedOSPlatformAttribute per annotare le API come specifiche della piattaforma e UnsupportedOSPlatformAttribute per 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.
- I metodi statici
Is<Platform>()
eIs<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
nella classe System.OperatingSystem 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. Vedere questi esempi del modo in cui questi metodi possono essere usati come guard di riferimenti API specifici della piattaforma.
Prerequisiti
L'analizzatore della compatibilità della piattaforma è uno degli analizzatori della qualità del codice Roslyn. A partire da .NET 5 questi analizzatori sono inclusi in .NET SDK. L'analizzatore della compatibilità della piattaforma è abilitato per impostazione predefinita solo per i progetti destinati a net5.0
o versione successiva. È tuttavia possibile abilitarlo per i progetti destinati ad altri framework.
Procedura con cui l'analizzatore determina la dipendenza della piattaforma
Un'API senza attributi viene considerata funzionante in tutte le piattaforme del sistema operativo.
Un'API contrassegnata con
[SupportedOSPlatform("platform")]
è considerata portabile solo nella piattaforma specificata e in tutte le piattaforme 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 è supportata anche la piattaforma superset. Ad esempio,
[SupportedOSPlatform("iOS")]
implica che l'API è supportata iniOS
e anche nella rispettiva piattaforma superset,MacCatalyst
. - L'analizzatore genererà un avviso se si fa riferimento ad API specifiche della piattaforma senza un contesto di piattaforma appropriato:
- Avvisa se il progetto non fa riferimento 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 multipiattaforma
<TargetFramework>net5.0</TargetFramework>
. - Non avvisa se viene fatto riferimento all'API specifica della piattaforma all'interno di un progetto destinato a una qualsiasi delle piattaforme specificate, ad esempio per un'API specifica di Windows chiamata da un progetto destinato a Windows
<TargetFramework>net5.0-windows</TargetFramework>
e se 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 protetta da
OperatingSystem.IsWindows()
. - Non avvisa se viene fatto riferimento all'API specifica della piattaforma dallo stesso contesto specifico della piattaforma, ad esempio anche il sito di chiamata ha l'attribuito
[SupportedOSPlatform("platform")
.
- Avvisa se il progetto non fa riferimento alla piattaforma supportata, ad esempio un'API specifica di Windows chiamata da un progetto destinato a iOS
- L'attributo può essere applicato più volte per indicare il supporto di più piattaforme, ad esempio
Un'API contrassegnata con
[UnsupportedOSPlatform("platform")]
viene considerata non supportata nella piattaforma specificata e in qualsiasi piattaforma di cui è un subset, ma è supportata per tutte le altre piattaforme.- L'attributo può essere applicato più volte con piattaforme diverse, ad esempio
[UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")]
. - Se la piattaforma è un subset di un'altra piattaforma, l'attributo implica che è supportata anche la piattaforma superset. Ad esempio,
[UnsupportedOSPlatform("iOS")]
implica che l'API non è supportata iniOS
e anche nella rispettiva piattaforma superset,MacCatalyst
. - L'analizzatore genera un avviso solo se
platform
è valida per il sito di chiamata:Avvisa se il progetto è destinato alla piattaforma con attributi non supportati, ad esempio se l'API ha l'attributo
[UnsupportedOSPlatform("windows")]
e il sito di chiamata fa riferimento a<TargetFramework>net5.0-windows</TargetFramework>
.Avvisa se il progetto ha più destinazioni e
platform
è incluso nel gruppo di elementi<SupportedPlatform>
di MSBuild predefinito oppureplatform
viene incluso manualmente all'interno del gruppo di elementiMSBuild
<SupportedPlatform>:<ItemGroup> <SupportedPlatform Include="platform" /> </ItemGroup>
Non avvisa se si sta creando un'app che non è destinata alla piattaforma non supportata o ha più destinazioni e la piattaforma non è inclusa nel gruppo di elementi
<SupportedPlatform>
di MSBuild predefinito.
- L'attributo può essere applicato più volte con piattaforme diverse, ad esempio
È possibile creare un'istanza di entrambi gli attributi con o senza numeri di versione come parte del nome della piattaforma. I numeri di versione hanno il formato
major.minor[.build[.revision]]
.major.minor
è obbligatorio e le partibuild
erevision
sono facoltative. Ad esempio, "Windows6.1" indica Windows versione 6.1, ma "Windows" viene interpretato come Windows 0.0.
Per altre informazioni, vedere gli esempi di funzionamento degli attributi e dei dati di diagnostica che producono.
Procedura con cui l'analizzatore riconosce le piattaforme di destinazione di 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 attributo SupportedOSPlatform
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 come specifico di Windows. Pertanto, la chiamata di API solo Windows con versione 7.0 o precedente non provocherebbe avvisi nel progetto.
Nota
Se la generazione del file AssemblyInfo.cs è disabilitata per il progetto, ovvero la proprietà <GenerateAssemblyInfo>
è impostata su false
, l'attributo SupportedOSPlatform
a livello 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 introduce il concetto di inclusione della piattaforma, in base al quale 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 tipo OperatingSystem ha un attributo SupportedOSPlatformGuard("supersetPlatform")]
, supersetPlatform
viene considerato un superset della piattaforma del sistema operativo controllata dal metodo.
Ad esempio, al metodo OperatingSystem.IsIOS() viene assegnato l'attributo [SupportedOSPlatformGuard("MacCatalyst")]
. Di conseguenza, si applicano le istruzioni seguenti:
- I metodi OperatingSystem.IsIOS() e OperatingSystem.IsIOSVersionAtLeast controllano non solo la piattaforma
iOS
, ma anche la piattaformaMacCatalyst
. [SupportedOSPlatform("iOS")]
implica che l'API è supportata iniOS
e anche nella rispettiva piattaforma superset,MacCatalyst
. È possibile usare l'attributo[UnsupportedOSPlatform("MacCatalyst")]
per escludere questo supporto implicito.[UnsupportedOSPlatform("iOS")
implica che l'API non è supportata iniOS
eMacCatalyst
. È 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) |
---|---|---|---|---|
Subset | ✔️ | ❌ | ✔️ | ❌ |
Superset | ✔️ | ✔️ | ✔️ | ✔️ |
Suggerimento
Le stesse regole si applicano agli attributi SupportedOSPlatformGuard
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 è presente una combinazione di attributi
[SupportedOSPlatform]
e[UnsupportedOSPlatform]
, tutti gli attributi vengono raggruppati in base all'identificatore della piattaforma del sistema operativo:Elenco dei soli elementi supportati. 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 rispetto alla versione minima supportata e ciò 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 dei soli 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 l'attributo[SupportedOSPlatform]
con la stessa piattaforma ma una versione successiva e ciò 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, questa è considerata un'incoerenza, che non è supportata per l'analizzatore. Se si verifica un'incoerenza, l'analizzatore ignora le piattaforme[UnsupportedOSPlatform]
.- Se le versioni più basse degli attributi
[SupportedOSPlatform]
e[UnsupportedOSPlatform]
sono uguali, l'analizzatore considera la piattaforma come parte dell'elenco dei soli elementi supportati.
- Se le versioni più basse degli attributi
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 superiore di
target
influiscono su tutti i relativi membri e tipi. - Gli attributi a livello figlio si applicano solo se rispettano la regola in base alla quale "le annotazioni figlio possono restringere il supporto delle piattaforme, ma non possono estenderlo".
- Quando l'elemento padre ha un elenco dei soli elementi supportati, gli attributi dei membri figlio non possono aggiungere un nuovo supporto per la piattaforma, in quanto ciò estenderebbe il supporto padre. Il supporto per una nuova piattaforma può essere aggiunto solo all'elemento padre stesso. L'elemento figlio può tuttavia avere l'attributo
Supported
per la stessa piattaforma con versioni successive, in quanto ciò restringe il supporto. L'elemento figlio può inoltre avere l'attributoUnsupported
con la stessa piattaforma, poiché anche ciò restringe il supporto padre. - Quando l'elemento padre ha un elenco dei soli elementi non supportati, gli attributi dei membri figlio possono aggiungere il supporto per una nuova piattaforma, in quanto ciò limita il supporto padre. Non può tuttavia avere l'attributo
Supported
per la stessa piattaforma dell'elemento padre, perché ciò estende il supporto padre. Il supporto per la stessa piattaforma può essere aggiunto solo all'elemento padre in cui è stato applicato l'attributoUnsupported
originale.
- Quando l'elemento padre ha un elenco dei soli elementi supportati, gli attributi dei membri figlio non possono aggiungere un nuovo supporto per la piattaforma, in quanto ciò estenderebbe il supporto padre. Il supporto per una nuova piattaforma può essere aggiunto solo all'elemento padre stesso. L'elemento figlio può tuttavia avere l'attributo
- Se
[SupportedOSPlatform("platformVersion")]
viene applicato più volte per un'API con lo stesso nomeplatform
, l'analizzatore considera solo quella con la versione minima. - Se
[UnsupportedOSPlatform("platformVersion")]
viene applicato più di due volte per un'API con lo stesso nomeplatform
, l'analizzatore considera solo le due con le versioni meno recenti.
Nota
Un'API supportata inizialmente ma non supportata (rimossa) in una versione successiva non dovrebbe essere supportata nuovamente in una versione ancora successiva.
- Gli attributi applicati al livello superiore di
Esempi di funzionamento degli attributi e dei dati di 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 questi dati di 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 l'opzione più appropriata per la situazione specifica:
Proteggere la chiamata. A tale scopo, è possibile chiamare in modo condizionale il codice in fase di esecuzione. Controllare se l'esecuzione avviene in una
Platform
desiderata usando uno dei metodi di controllo della piattaforma, ad esempioOperatingSystem.Is<Platform>()
oOperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0)
. Esempio.Contrassegnare il sito di chiamata come specifico della piattaforma. È anche possibile scegliere di contrassegnare le API come specifiche della piattaforma, in modo da inoltrare semplicemente in modo efficace i requisiti ai chiamanti. Contrassegnare il metodo contenitore o il tipo oppure l'intero assembly con gli stessi attributi della chiamata dipendente dalla piattaforma a cui si fa riferimento. Esempi.
Dichiarare il sito di chiamata con il controllo della piattaforma. Se si vuole evitare l'overhead di un'istruzione
if
aggiuntiva in fase di esecuzione, usare Debug.Assert(Boolean). Esempio.Eliminare il codice. Questa opzione non è in genere consigliata perché comporta la perdita di 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 rispetto ad API specifiche della piattaforma.
Disabilitare l'avviso. È anche possibile disabilitare semplicemente l'avviso tramite una voce di EditorConfig o
#pragma warning disable CA1416
. Questa opzione deve essere tuttavia un'ultima risorsa quando si usano API specifiche della piattaforma.Suggerimento
Quando si disabilitano gli avvisi usando le direttive
#pragma
del pre-compilatore, gli identificatori a cui si fa riferimento applicano la distinzione tra maiuscole e minuscole. Ad esempio,ca1416
non disabiliterebbe effettivamente l'avviso CA1416.
Proteggere le API specifiche della piattaforma con metodi guard
Il nome della piattaforma del metodo guard deve corrispondere al nome della piattaforma dell'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 guardversion
deve essere maggiore o uguale aVersion
della piattaforma chiamante.Per l'attributo
[UnsupportedOSPlatform("platformVersion")]
, la piattaforma del metodo guardversion
deve essere minore o uguale aVersion
della piattaforma 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 a
netstandard
onetcoreapp
in cui non sono disponibili nuove API OperatingSystem, l'API RuntimeInformation.IsOSPlatform può essere usata e verrà rispettata dall'analizzatore. Non è tuttavia ottimizzata come le nuove API aggiunte in OperatingSystem. Se la piattaforma non è supportata nello struct OSPlatform, è possibile chiamare OSPlatform.Create(String) e passare il nome della piattaforma, che viene rispettato anche dall'analizzatore.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 guard della piattaforma e usarli come guard personalizzati
Come illustrato in precedenza, l'analizzatore riconosce i metodi statici guard della piattaforma OperatingSystem, ad esempio OperatingSystem.IsWindows
e anche RuntimeInformation.IsOSPlatform. È tuttavia consigliabile memorizzare nella cache il risultato del guard in un campo e riutilizzarlo oppure usare metodi guard personalizzati per controllare una piattaforma. L'analizzatore deve riconoscere tali API come guard personalizzati e non deve generare avvisi per le API protette da tali guard. Gli attributi guard sono stati introdotti in .NET 6 per supportare questo scenario:
SupportedOSPlatformGuardAttribute
annota le API che possono essere usate come guard per le API annotate con SupportedOSPlatformAttribute.UnsupportedOSPlatformGuardAttribute
annota le API che possono essere usate come guard per le API annotate con UnsupportedOSPlatformAttribute.
Questi attributi possono includere facoltativamente 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 del sito di chiamataversion
deve essere maggiore o uguale aVersion
della piattaforma chiamantePer l'attributo
[UnsupportedOSPlatform("platformVersion")]
, la piattaforma del sito di chiamataversion
deve essere minore o uguale aVersion
della piattaforma chiamante// 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(); }
Dichiarare il sito di chiamata con il controllo della piattaforma
Tutti i controlli condizionali usati negli esempi di guard della piattaforma 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
}