Platformcompatibiliteitsanalyse

U hebt waarschijnlijk het motto van 'One .NET' gehoord: één geïntegreerd platform voor het bouwen van elk type toepassing. De .NET 5 SDK bevat ASP.NET Core, Entity Framework Core, WinForms, WPF, Xamarin en ML.NET, en biedt in de loop van de tijd ondersteuning voor meer platforms. .NET 5 streeft ernaar om een ervaring te bieden waarbij u niet hoeft te redeneren over de verschillende smaken van .NET, maar niet probeert het onderliggende besturingssysteem (OS) volledig te abstraheren. U kunt nog steeds platformspecifieke API's aanroepen, zoals P/Invokes, WinRT of de Xamarin-bindingen voor iOS en Android.

Maar het gebruik van platformspecifieke API's voor een onderdeel betekent dat de code niet meer werkt op alle platforms. We hebben een manier nodig om dit tijdens het ontwerp te detecteren, zodat ontwikkelaars per ongeluk diagnostische gegevens krijgen wanneer ze per ongeluk platformspecifieke API's gebruiken. Om dit doel te bereiken, introduceert .NET 5 de platformcompatibiliteitsanalyse en aanvullende API's om ontwikkelaars te helpen platformspecifieke API's te identificeren en te gebruiken, indien van toepassing.

De nieuwe API's zijn onder andere:

  • SupportedOSPlatformAttribute als u aantekeningen wilt maken voor API's als platformspecifiek en UnsupportedOSPlatformAttribute om aantekeningen te maken bij API's die niet worden ondersteund op een bepaald besturingssysteem. Deze kenmerken kunnen eventueel het versienummer bevatten en zijn al toegepast op bepaalde platformspecifieke API's in de kernbibliotheken van .NET.
  • Is<Platform>() en Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) statische methoden in de System.OperatingSystem klasse voor het veilig aanroepen van platformspecifieke API's. Kan bijvoorbeeld OperatingSystem.IsWindows() worden gebruikt om een aanroep van een Windows-specifieke API te bewaken en OperatingSystem.IsWindowsVersionAtLeast() kan worden gebruikt om een windows-specifieke API-aanroep te bewaken. Bekijk deze voorbeelden van hoe deze methoden kunnen worden gebruikt als beveiliging van platformspecifieke API-verwijzingen.

Vereisten

De platformcompatibiliteitsanalyse is een van de Roslyn-codekwaliteitsanalyses. Vanaf .NET 5 zijn deze analyses opgenomen in de .NET SDK. De platformcompatibiliteitsanalyse is standaard alleen ingeschakeld voor projecten die zijn gericht op net5.0 of een latere versie. U kunt deze echter inschakelen voor projecten die zijn gericht op andere frameworks.

Hoe de analyse platformafhankelijkheid bepaalt

  • Een niet-toegewezen API wordt beschouwd als werken op alle besturingssysteemplatforms.

  • Een API die is gemarkeerd met [SupportedOSPlatform("platform")] , wordt beschouwd als alleen draagbaar voor het opgegeven platform en alle platforms waarvan het een subset is.

    • Het kenmerk kan meerdere keren worden toegepast om meerdere platformondersteuning aan te geven, bijvoorbeeld[SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Als het platform een subset van een ander platform is, impliceert het kenmerk dat het supersetplatform ook wordt ondersteund. Impliceert bijvoorbeeld [SupportedOSPlatform("iOS")] dat de API wordt ondersteund op iOS en ook op het supersetplatform, MacCatalyst.
    • De analyzer produceert een waarschuwing als er naar platformspecifieke API's wordt verwezen zonder een juiste platformcontext:
      • Waarschuwt als het project niet is gericht op het ondersteunde platform (bijvoorbeeld een Windows-specifieke API die wordt aangeroepen vanuit een project dat is gericht op iOS <TargetFramework>net5.0-ios14.0</TargetFramework>).
      • Waarschuwt of het project platformoverschrijdende API's is en platformspecifieke API's aanroept (bijvoorbeeld een Windows-specifieke API die wordt aangeroepen vanuit platformoverschrijdende TFM <TargetFramework>net5.0</TargetFramework>).
      • Waarschuwt niet als wordt verwezen naar de platformspecifieke API binnen een project dat is gericht op een van de opgegeven platforms (bijvoorbeeld voor een Windows-specifieke API die wordt aangeroepen vanuit een project gericht op vensters <TargetFramework>net5.0-windows</TargetFramework> en de AssemblyInfo.cs bestandsgeneratie is ingeschakeld voor het project).
      • Waarschuwt niet als de platformspecifieke API-aanroep wordt beveiligd door bijbehorende platformcontrolemethoden (bijvoorbeeld een Windows-specifieke API-aanroep die wordt beveiligd door OperatingSystem.IsWindows()).
      • Waarschuwt niet als naar de platformspecifieke API wordt verwezen vanuit dezelfde platformspecifieke context (aanroepsite ook toegeschreven aan[SupportedOSPlatform("platform")).
  • Een API die is gemarkeerd met [UnsupportedOSPlatform("platform")] , wordt beschouwd als niet-ondersteund op het opgegeven platform en alle platforms waarvan het een subset is, maar wordt ondersteund voor alle andere platforms.

    • Het kenmerk kan meerdere keren worden toegepast met verschillende platforms, bijvoorbeeld [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")].
    • Als het platform een subset van een ander platform is, impliceert het kenmerk dat het supersetplatform ook niet wordt ondersteund. Impliceert bijvoorbeeld [UnsupportedOSPlatform("iOS")] dat de API niet wordt ondersteund op iOS en ook op het supersetplatform, MacCatalyst.
    • De analyse produceert alleen een waarschuwing als de platform functie effectief is voor de oproepsite:
      • Waarschuwt of het project is gericht op het platform dat is toegeschreven aan niet-ondersteund (bijvoorbeeld als de API is toegewezen aan [UnsupportedOSPlatform("windows")] en de doeldoelen <TargetFramework>net5.0-windows</TargetFramework>van de aanroepsite).

      • Waarschuwt of het project multi-targeted is en de platform is opgenomen in de standaard MSBuild-itemsgroep <SupportedPlatform> , of het platform is handmatig opgenomen in de MSBuild<groep SupportedPlatform-items> :

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • Waarschuwt niet als u een app bouwt die niet is gericht op het niet-ondersteunde platform of als het platform niet op meerdere doelen is gericht en het platform niet is opgenomen in de standaardgroep MSBuild-items <SupportedPlatform> .

  • Beide kenmerken kunnen worden geïnstantieerd met of zonder versienummers als onderdeel van de platformnaam. Versienummers hebben de notatie ; major.minor[.build[.revision]]major.minor is vereist en de buildrevision onderdelen zijn optioneel. 'Windows6.1' geeft bijvoorbeeld Windows versie 6.1 aan, maar 'Windows' wordt geïnterpreteerd als Windows 0.0.

Zie voorbeelden van hoe de kenmerken werken en welke diagnostische gegevens ze veroorzaken voor meer informatie.

Hoe de analyzer TFM-doelplatforms herkent

De analyzer controleert geen doelframework moniker (TFM) doelplatforms van MSBuild-eigenschappen, zoals <TargetFramework> of <TargetFrameworks>. Als de TFM een doelplatform heeft, injecteert MSBuild een SupportedOSPlatform kenmerk met de doelplatformnaam in het AssemblyInfo.cs-bestand , dat wordt gebruikt door de analyse. Als de TFM bijvoorbeeld is net5.0-windows10.0.19041, injecteert MSBuild het [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] kenmerk in het AssemblyInfo.cs-bestand en wordt de hele assembly als alleen Windows beschouwd. Daarom zou het aanroepen van windows-API's met versie 7.0 of lager geen waarschuwingen in het project veroorzaken.

Notitie

Als het AssemblyInfo.cs bestandsgeneratie is uitgeschakeld voor het project (dat wil gezegd, de <GenerateAssemblyInfo> eigenschap is ingesteld op false), kan het vereiste kenmerk op assemblyniveau SupportedOSPlatform niet worden toegevoegd door MSBuild. In dit geval ziet u waarschuwingen voor het gebruik van platformspecifieke API's, zelfs als u zich op dat platform richt. Als u de waarschuwingen wilt oplossen, schakelt u het AssemblyInfo.cs bestandsgeneratie in of voegt u het kenmerk handmatig toe aan uw project.

Platformopname

.NET 6 introduceert het concept van platformopname, waarbij één platform een subset van een ander platform kan zijn. Een aantekening voor het subsetplatform impliceert dezelfde ondersteuning (of het ontbreken daarvan) voor het supersetplatform. Als een platformcontrolemethode in het OperatingSystem type een SupportedOSPlatformGuard("supersetPlatform")] kenmerk heeft, supersetPlatform wordt dit beschouwd als een superset van het besturingssysteemplatform waarop de methode controleert.

De methode wordt bijvoorbeeld OperatingSystem.IsIOS() toegeschreven [SupportedOSPlatformGuard("MacCatalyst")]. Daarom zijn de volgende instructies van toepassing:

  • De OperatingSystem.IsIOS() en OperatingSystem.IsIOSVersionAtLeast methoden controleren niet alleen het iOS platform, maar ook het MacCatalyst platform.
  • [SupportedOSPlatform("iOS")] impliceert dat de API wordt ondersteund op iOS en ook op het supersetplatform, MacCatalyst. U kunt het [UnsupportedOSPlatform("MacCatalyst")] kenmerk gebruiken om deze impliciete ondersteuning uit te sluiten.
  • [UnsupportedOSPlatform("iOS") impliceert dat de API niet wordt ondersteund op iOS en MacCatalyst. U kunt het [SupportedOSPlatform("MacCatalyst")] kenmerk gebruiken om dit impliciete gebrek aan ondersteuning uit te sluiten.

Bekijk de volgende dekkingsmatrix, waarbij ✔️ wordt aangegeven dat het platform wordt ondersteund en ❌ dat het platform niet wordt ondersteund.

Platform SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
Subset ✔️ ✔️
Superset ✔️ ✔️ ✔️ ✔️

Tip

Dezelfde regels gelden voor de SupportedOSPlatformGuard en UnsupportedOSPlatformGuard kenmerken.

In het volgende codefragment ziet u hoe u kenmerken kunt combineren om het juiste ondersteuningsniveau in te stellen.

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

Geavanceerde scenario's voor kenmerkcombinaties

  • Als er een combinatie van [SupportedOSPlatform] kenmerken aanwezig [UnsupportedOSPlatform] is, worden alle kenmerken gegroepeerd op platform-id van het besturingssysteem:

    • Alleen lijst ondersteund. Als de laagste versie voor elk besturingssysteemplatform een [SupportedOSPlatform] kenmerk is, wordt de API beschouwd als alleen ondersteund door de vermelde platforms en niet ondersteund door alle andere platforms. De optionele [UnsupportedOSPlatform] kenmerken voor elk platform kunnen alleen een hogere versie van de minimaal ondersteunde versie hebben, wat aangeeft dat de API wordt verwijderd vanaf de opgegeven versie.

      // 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();
      
    • Lijst met alleen ondersteunde bestanden. Als de laagste versie voor elk besturingssysteemplatform een [UnsupportedOSPlatform] kenmerk is, wordt de API beschouwd als alleen niet ondersteund door de vermelde platforms en ondersteund door alle andere platforms. De lijst kan een kenmerk hebben [SupportedOSPlatform] met hetzelfde platform, maar een hogere versie, die aangeeft dat de API wordt ondersteund vanaf die versie.

      // 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();
      
    • Inconsistente lijst. Als de laagste versie voor sommige platforms is [SupportedOSPlatform] terwijl het voor andere platforms is [UnsupportedOSPlatform] , wordt deze beschouwd als inconsistent, wat niet wordt ondersteund voor de analyse. Als inconsistentie optreedt, negeert de analyse de [UnsupportedOSPlatform] platforms.

      • Als de laagste versies van [SupportedOSPlatform] en [UnsupportedOSPlatform] kenmerken gelijk zijn, beschouwt de analyzer het platform als onderdeel van de lijst Alleen ondersteund.
  • Platformkenmerken kunnen worden toegepast op typen, leden (methoden, velden, eigenschappen en gebeurtenissen) en assembly's met verschillende platformnamen of versies.

    • Kenmerken die op het hoogste niveau target worden toegepast, zijn van invloed op alle leden en typen.
    • Kenmerken op onderliggend niveau zijn alleen van toepassing als ze voldoen aan de regel 'onderliggende aantekeningen kunnen de ondersteuning voor platforms beperken, maar ze kunnen deze niet breder maken'.
      • Als bovenliggende lijst alleen ondersteund heeft, kunnen onderliggende lidkenmerken geen nieuwe platformondersteuning toevoegen, omdat dat bovenliggende ondersteuning zou kunnen uitbreiden. Ondersteuning voor een nieuw platform kan alleen worden toegevoegd aan het bovenliggende platform zelf. Maar het onderliggende element kan het Supported kenmerk voor hetzelfde platform hebben met latere versies, omdat dit de ondersteuning beperkt. Het onderliggende element kan ook het Unsupported kenmerk hebben met hetzelfde platform als dat ook ondersteuning voor ouders beperkt.
      • Wanneer de bovenliggende lijst alleen niet wordt ondersteund, kunnen onderliggende lidkenmerken ondersteuning voor een nieuw platform toevoegen, omdat hiermee ondersteuning voor bovenliggende ondersteuning wordt beperkt. Maar het kan niet het Supported kenmerk hebben voor hetzelfde platform als het bovenliggende platform, omdat dit de bovenliggende ondersteuning uitbreidt. Ondersteuning voor hetzelfde platform kan alleen worden toegevoegd aan het bovenliggende element waarop het oorspronkelijke Unsupported kenmerk is toegepast.
    • Als [SupportedOSPlatform("platformVersion")] er meerdere keren voor een API met dezelfde platform naam wordt toegepast, houdt de analyzer alleen rekening met de api met de minimale versie.
    • Als [UnsupportedOSPlatform("platformVersion")] er meer dan twee keer voor een API met dezelfde platform naam wordt toegepast, worden de twee alleen met de vroegste versies beschouwd.

    Notitie

    Een API die in eerste instantie werd ondersteund, maar niet wordt ondersteund (verwijderd) in een latere versie, wordt naar verwachting niet opnieuw ondersteund in een latere versie.

Voorbeelden van hoe de kenmerken werken en welke diagnostische gegevens ze produceren

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

Gerapporteerde waarschuwingen verwerken

De aanbevolen manier om met deze diagnostische gegevens om te gaan, is ervoor te zorgen dat u alleen platformspecifieke API's aanroept wanneer u op een geschikt platform wordt uitgevoerd. Hieronder vindt u de opties die u kunt gebruiken om de waarschuwingen aan te pakken; kies welke het meest geschikt is voor uw situatie:

  • Beveilig het gesprek. U kunt dit bereiken door de code voorwaardelijk aan te roepen tijdens runtime. Controleer of u op een gewenste manier Platform werkt met behulp van een van de platformcontrolemethoden, bijvoorbeeld OperatingSystem.Is<Platform>() of OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0). Voorbeeld.

  • Markeer de oproepsite als platformspecifiek. U kunt er ook voor kiezen om uw eigen API's te markeren als platformspecifiek, waardoor u de vereisten effectief doorstuurt naar uw bellers. Markeer de bijbehorende methode of het type of de hele assembly met dezelfde kenmerken als de aanroep waarnaar wordt verwezen. Voorbeelden.

  • Bevestig de oproepsite met platformcontrole. Als u de overhead van een extra if instructie tijdens runtime niet wilt, gebruikt u Debug.Assert(Boolean). Voorbeeld.

  • Verwijder de code. Over het algemeen niet wat u wilt, omdat dit betekent dat u betrouwbaarheid verliest wanneer uw code wordt gebruikt door Windows-gebruikers. Voor gevallen waarin een platformoverschrijdend alternatief bestaat, kunt u deze waarschijnlijk beter gebruiken via platformspecifieke API's.

  • De waarschuwing onderdrukken. U kunt de waarschuwing ook gewoon onderdrukken via een EditorConfig-vermelding of #pragma warning disable CA1416. Deze optie moet echter een laatste redmiddel zijn bij het gebruik van platformspecifieke API's.

    Tip

    Wanneer u waarschuwingen uitschakelt met behulp van de #pragma richtlijnen vóór de compiler, zijn de id's die u wilt gebruiken hoofdlettergevoelig. Zou bijvoorbeeld ca1416 de waarschuwing CA1416 niet daadwerkelijk uitschakelen.

Platformspecifieke API's bewaken met beveiligingsmethoden

De platformnaam van de guard-methode moet overeenkomen met de naam van het aanroepende platformafhankelijke API-platform. Als de platformtekenreeks van de aanroepende API de versie bevat:

  • Voor het [SupportedOSPlatform("platformVersion")] kenmerk moet het platform voor de guard-methode version groter zijn dan of gelijk zijn aan het aanroepende platform Version.

  • Voor het [UnsupportedOSPlatform("platformVersion")] kenmerk moet het platform version van de guard-methode kleiner zijn dan of gelijk zijn aan het aanroepende platform Version.

    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
        }
    }
    
  • Als u code wilt beveiligen die is gericht netstandard op of netcoreapp waar geen nieuwe OperatingSystem API's beschikbaar zijn, kan de RuntimeInformation.IsOSPlatform API worden gebruikt en wordt deze door de analyse gerespecteerd. Maar het is niet zo geoptimaliseerd als de nieuwe API's die zijn toegevoegd.OperatingSystem Als het platform niet wordt ondersteund in de OSPlatform struct, kunt u de platformnaam aanroepen OSPlatform.Create(String) en doorgeven, die de analyse ook respecteert.

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

Aantekeningen toevoegen aan API's met platformbeveiligingskenmerken en deze gebruiken als een aangepaste beveiliging

Zoals eerder weergegeven, herkent de analyse de statische platformbeveiligingsmethoden in het OperatingSystem type, zoals OperatingSystem.IsWindows, en ook RuntimeInformation.IsOSPlatform. Mogelijk wilt u het beveiligingsresultaat echter in de cache opslaan in een veld en opnieuw gebruiken, of aangepaste beveiligingsmethoden gebruiken om een platform te controleren. De analyse moet dergelijke API's herkennen als een aangepaste beveiliging en moet niet waarschuwen voor de API's die door hen worden bewaakt. De guard-kenmerken zijn geïntroduceerd in .NET 6 ter ondersteuning van dit scenario:

  • SupportedOSPlatformGuardAttribute maakt aantekeningen bij API's die kunnen worden gebruikt als een bewaker voor API's met SupportedOSPlatformAttributeaantekeningen.
  • UnsupportedOSPlatformGuardAttribute maakt aantekeningen bij API's die kunnen worden gebruikt als een bewaker voor API's met UnsupportedOSPlatformAttributeaantekeningen.

Deze kenmerken kunnen eventueel een versienummer bevatten. Ze kunnen meerdere keren worden toegepast om meer dan één platform te bewaken en kunnen worden gebruikt voor het toevoegen van aantekeningen aan een veld, eigenschap of methode.

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

Oproepsite markeren als platformspecifiek

Platformnamen moeten overeenkomen met de aanroepende platformafhankelijke API. Als de platformtekenreeks een versie bevat:

  • Voor het [SupportedOSPlatform("platformVersion")] kenmerk moet het oproepsiteplatform version groter zijn dan of gelijk zijn aan het aanroepende platform Version

  • Voor het [UnsupportedOSPlatform("platformVersion")] kenmerk moet het oproepsiteplatform version kleiner zijn dan of gelijk zijn aan het belplatform 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();
    }
    

De oproepsite bevestigen met platformcontrole

Alle voorwaardelijke controles die in de platformbeveiligingsvoorbeelden worden gebruikt, kunnen ook worden gebruikt als voorwaarde voor 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
}

Zie ook