Platformkompatibilitás-elemző

Valószínűleg már hallotta a "One .NET" mottóját: egyetlen, egységes platform bármilyen típusú alkalmazás létrehozásához. A .NET 5 SDK tartalmazza a ASP.NET Core, az Entity Framework Core, a WinForms, a WPF, a Xamarin és a ML.NET-et, és idővel további platformok támogatását is biztosítja. A .NET 5 arra törekszik, hogy olyan élményt nyújtson, amelyben nem kell érvelnie a .NET különböző ízei miatt, de nem kísérli meg teljesen absztrakcióval eltávolodni a mögöttes operációs rendszertől (OS). Továbbra is meghívhat platformspecifikus API-kat, például P/Invokes, WinRT vagy xamarin kötéseket iOS és Android rendszeren.

A platformspecifikus API-k egy összetevőn való használata azonban azt jelenti, hogy a kód már nem működik az összes platformon. Ezt a tervezéskor kellett észlelni, hogy a fejlesztők diagnosztikát kapjanak, amikor véletlenül platformspecifikus API-kat használnak. E cél elérése érdekében a .NET 5 bevezeti a platformkompatibilitás-elemzőt és a kiegészítő API-kat, amelyek segítenek a fejlesztőknek adott esetben a platformspecifikus API-k azonosításában és használatában.

Az új API-k a következők:

  • SupportedOSPlatformAttribute az API-k platformspecifikusként történő jegyzetelése, valamint UnsupportedOSPlatformAttribute az API-k megjegyzésekkel való ellátása, mivel az adott operációs rendszeren nem támogatottak. Ezek az attribútumok opcionálisan tartalmazhatják a verziószámot, és már alkalmazva lettek néhány platformspecifikus API-ra az alapvető .NET-kódtárakban.
  • Is<Platform>() és Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) statikus metódusok az System.OperatingSystem osztályban a platformspecifikus API-k biztonságos meghívásához. Például OperatingSystem.IsWindows() egy Windows-specifikus API-ra irányuló hívások őrzésére használható, és OperatingSystem.IsWindowsVersionAtLeast() egy verziószámozott Windows-specifikus API-hívás őrzésére. Tekintse meg ezeket a példákat, amelyek bemutatja, hogyan használhatók ezek a metódusok platformspecifikus API-referenciák őreiként.

Előfeltételek

A platformkompatibilitás-elemző a Roslyn-kódminőség-elemzők egyike. A .NET 5-tel kezdődően ezek az elemzők a .NET SDK részét képezik. A platformkompatibilitás-elemző alapértelmezés szerint csak a megcélzott net5.0 vagy újabb verziójú projektek esetében engedélyezett. Azonban más keretrendszereket célzó projektekhez is engedélyezheti .

Hogyan határozza meg az elemző a platformfüggőséget?

  • A nem felügyelt API-kminden operációsrendszer-platformon működnek.

  • A megjelölt [SupportedOSPlatform("platform")] API-k csak a megadott platformon hordozhatónak tekinthetők, és minden olyan platformon, amelynek az alkészlete.

    • Az attribútum többször is alkalmazható több platform támogatásának jelzésére, például [SupportedOSPlatform("windows"), SupportedOSPlatform("Android29.0")].
    • Ha a platform egy másik platform részhalmaza, az attribútum azt jelenti, hogy a szuperhalmazplatform is támogatott. Ez például azt jelenti, [SupportedOSPlatform("iOS")] hogy az API a superset platformon iOS is támogatott. MacCatalyst
    • Az elemző figyelmeztetést küld, ha a platformspecifikus API-kra megfelelő platformkörnyezet nélkül hivatkoznak:
      • Figyelmeztet, ha a projekt nem a támogatott platformot célozza (például egy iOS-t <TargetFramework>net5.0-ios14.0</TargetFramework>célzó projektből hívott Windows-specifikus API-t).
      • Figyelmeztet, ha a projekt platformfüggetlen, és platformspecifikus API-kat hív meg (például egy platformfüggetlen TFM-ből <TargetFramework>net5.0</TargetFramework>hívott Windows-specifikus API-t).
      • Nem figyelmeztet, ha a platformspecifikus API-ra hivatkozik egy olyan projektben, amely a megadott platformok bármelyikét célozza (például egy olyan Windows-specifikus API esetében, amely egy olyan projektből van meghívva, amely windowsos<TargetFramework>net5.0-windows</TargetFramework>, és a AssemblyInfo.cs fájlgenerálás engedélyezve van a projekthez).
      • Nem figyelmeztet, ha a platformspecifikus API-hívást a megfelelő platformellenőrzési módszerek (például egy Windows-specifikus API-hívás őrziOperatingSystem.IsWindows()).
      • Nem figyelmeztet, ha a platformspecifikus API-ra ugyanabból a platformspecifikus környezetből hivatkozik (a hívási hely is hozzá van rendelve[SupportedOSPlatform("platform")).
  • A megjelölt [UnsupportedOSPlatform("platform")] API-k nem támogatottak a megadott platformon, és az összes többi platformon is támogatottak.

    • Az attribútum többször is alkalmazható különböző platformokon, például [UnsupportedOSPlatform("iOS"), UnsupportedOSPlatform("Android29.0")].
    • Ha a platform egy másik platform részhalmaza, az attribútum azt jelenti, hogy a szuperhalmazplatform szintén nem támogatott. Ez azt jelenti például, [UnsupportedOSPlatform("iOS")] hogy az API nem támogatott a iOS superset platformon és annak superset platformján is. MacCatalyst
    • Az elemző csak akkor állít elő figyelmeztetést , ha a platform hívási hely érvényes:
      • Figyelmezteti , ha a projekt a nem támogatottnak tulajdonított platformot célozza meg (például ha az API attribútuma [UnsupportedOSPlatform("windows")] és a hívási hely céljai <TargetFramework>net5.0-windows</TargetFramework>).

      • Figyelmezteti , ha a projekt több célzott, és az platform alapértelmezett MSBuild <SupportedPlatform> elemcsoport része, vagy manuálisan szerepel a platformMSBuild<Támogatottplatform-elemek> csoportban:

        <ItemGroup>
            <SupportedPlatform Include="platform" />
        </ItemGroup>
        
      • Nem figyelmeztet , ha olyan alkalmazást készít, amely nem a nem támogatott platformot célozza, vagy több-célzott, és a platform nem szerepel az alapértelmezett MSBuild <SupportedPlatform> elemek csoportjában.

  • Mindkét attribútum példányosítható verziószámokkal vagy anélkül a platformnév részeként. A verziószámok formátuma major.minor[.build[.revision]]; major.minor kötelező, és az buildrevision alkatrészek nem kötelezőek. A "Windows6.1" például azt jelzi, Windows 6.1-es verziót, de a "Windows" Windows 0.0-s verzióként van értelmezve.

További információkért tekintse meg az attribútumok működését és az általuk okozott diagnosztikát.

Hogyan ismeri fel az elemző a TFM-célplatformokat?

Az elemző nem ellenőrzi a célkeret-moniker (TFM) célplatformokat az MSBuild tulajdonságokból, például <TargetFramework> vagy <TargetFrameworks>. Ha a TFM célplatformmal rendelkezik, az MSBuild egy attribútumot szúr be SupportedOSPlatform a megcélzott platform nevével a AssemblyInfo.cs fájlba, amelyet az elemző használ fel. Ha például a TFM aznet5.0-windows10.0.19041, az MSBuild beszúrja az [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] attribútumot a AssemblyInfo.cs fájlba, és a teljes szerelvény csak Windows. Ezért a Windows csak 7.0-s vagy újabb verziójú API-k meghívása nem okozna figyelmeztetést a projektben.

Megjegyzés

Ha a AssemblyInfo.cs fájl létrehozása le van tiltva a projekthez (azaz a <GenerateAssemblyInfo> tulajdonság értéke false), az MSBuild nem tudja hozzáadni a szükséges szerelvényszintű SupportedOSPlatform attribútumot. Ebben az esetben a platformspecifikus API-k használatára vonatkozó figyelmeztetések akkor is megjelenhetnek, ha ezt a platformot célozza. A figyelmeztetések feloldásához engedélyezze a AssemblyInfo.cs fájlgenerálást, vagy adja hozzá manuálisan az attribútumot a projekthez.

Platformbefoglalás

A .NET 6 bevezeti a platformbefoglalás fogalmát, ahol az egyik platform egy másik platform részhalmaza lehet. Az alhalmazplatformhoz tartozó széljegyzetek a szuperhalmazplatform ugyanazon támogatását (vagy annak hiányát) jelentik. Ha a típusban egy OperatingSystem platformellenőrzési metódus rendelkezik SupportedOSPlatformGuard("supersetPlatform")] attribútummal, akkor supersetPlatform a rendszer az operációsrendszer-platform azon szuperhalmazának tekinti, amelyet a metódus ellenőriz.

A metódus attribútuma [SupportedOSPlatformGuard("MacCatalyst")]például OperatingSystem.IsIOS() . Ezért a következő állítások érvényesek:

  • A OperatingSystem.IsIOS() metódusok nemcsak OperatingSystem.IsIOSVersionAtLeast a platformot, hanem a iOS platformot is ellenőrzik MacCatalyst .
  • [SupportedOSPlatform("iOS")] azt jelenti, hogy az API a superset platformon iOS és annak platformján is támogatott, MacCatalyst. Az attribútummal kizárhatja ezt a [UnsupportedOSPlatform("MacCatalyst")] vélelmezett támogatást.
  • [UnsupportedOSPlatform("iOS") azt jelenti, hogy az API nem támogatott, iOS és MacCatalyst. Az attribútum használatával kizárhatja ezt a [SupportedOSPlatform("MacCatalyst")] vélelmezett támogatáshiányt.

Vegye figyelembe a következő lefedettségi mátrixot, amely ✔️ azt jelzi, hogy a platform támogatott, és ❌ azt jelzi, hogy a platform nem támogatott.

Platform SupportedOSPlatform(subset) SupportedOSPlatform(superset) UnsupportedOSPlatform(subset) UnsupportedOSPlatform(superset)
Részhalmazát ✔️ ✔️
Felülbírálja ✔️ ✔️ ✔️ ✔️

Tipp

Ugyanezek a szabályok vonatkoznak az és UnsupportedOSPlatformGuard az SupportedOSPlatformGuard attribútumokra is.

Az alábbi kódrészlet bemutatja, hogyan kombinálhatja az attribútumokat a megfelelő támogatási szint beállításához.

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

Speciális forgatókönyvek attribútumkombinációkhoz

  • Ha az attribútumok és [UnsupportedOSPlatform] az [SupportedOSPlatform] attribútumok kombinációja van jelen, az összes attribútum az operációs rendszer platformazonosítója szerint van csoportosítva:

    • Csak támogatott lista. Ha az egyes operációsrendszer-platformok legalacsonyabb verziója egy [SupportedOSPlatform] attribútum, az API-t csak a felsorolt platformok támogatják, és az összes többi platform nem támogatja. Az egyes platformok opcionális [UnsupportedOSPlatform] attribútumai csak a minimálisan támogatott verzió magasabb verziójával rendelkezhetnek, ami azt jelzi, hogy az API a megadott verziótól kezdve el lett távolítva.

      // 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();
      
    • Nem támogatott csak lista. Ha az egyes operációsrendszer-platformok legalacsonyabb verziója egy [UnsupportedOSPlatform] attribútum, akkor az API-t csak a felsorolt platformok nem támogatják, és az összes többi platform támogatja. A lista rendelkezhet [SupportedOSPlatform] ugyanahhoz a platformhoz tartozó attribútummal, de egy magasabb verzióval, ami azt jelzi, hogy az API az adott verziótól kezdve támogatott.

      // 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();
      
    • Inkonzisztens lista. Ha egyes platformok [SupportedOSPlatform][UnsupportedOSPlatform] legalacsonyabb verziója más platformokhoz tartozik, akkor inkonzisztensnek minősül, ami az elemző számára nem támogatott. Inkonzisztencia esetén az elemző figyelmen kívül hagyja a [UnsupportedOSPlatform] platformokat.

      • Ha az attribútumok és [UnsupportedOSPlatform] az [SupportedOSPlatform] attribútumok legalacsonyabb verziói egyenlők, az elemző a platformot csak a támogatott lista részeként tekinti.
  • A platformattribútumok különböző platformnevekkel vagy -verziókkal rendelkező típusokra, tagokra (metódusokra, mezőkre, tulajdonságokra és eseményekre) és szerelvényekre alkalmazhatók.

    • A legfelső szinten target alkalmazott attribútumok az összes tagot és típust érintik.
    • A gyermekszintű attribútumok csak akkor érvényesek, ha betartják a "gyermekjegyzetek szűkíthetik a platformok támogatását, de nem bővíthetik azt".
      • Ha a szülő csak támogatott listával rendelkezik, akkor a gyermektag-attribútumok nem adhatnak hozzá új platformtámogatást, mivel ez kiterjesztené a szülőtámogatást. Az új platform támogatása csak a szülőhöz adható hozzá. A gyermek azonban rendelkezhet ugyanahhoz a Supported platformhoz tartozó attribútummal, amely későbbi verziókkal rendelkezik, mint ami szűkíti a támogatást. Emellett a gyermek ugyanazzal a platformmal rendelkezhet az Unsupported attribútummal, amely a szülőtámogatást is szűkíti.
      • Ha a szülő nem támogatott csak listával rendelkezik, akkor a gyermektag-attribútumok támogatást adhatnak egy új platformhoz, mivel ez szűkíti a szülőtámogatást. De nem rendelkezhet ugyanazzal a Supported platformmal, mint a szülő, mert ez kiterjeszti a szülőtámogatást. Ugyanannak a platformnak a támogatása csak az eredeti Unsupported attribútumot alkalmazó szülőhöz adható hozzá.
    • Ha [SupportedOSPlatform("platformVersion")] többször alkalmazva van egy azonos platform nevű API-ra, az elemző csak a minimális verzióval rendelkezőt veszi figyelembe.
    • Ha [UnsupportedOSPlatform("platformVersion")] egy azonos platform nevű API-hoz kétszer több van alkalmazva, az elemző csak a legkorábbi verzióval rendelkező kettőt veszi figyelembe.

    Megjegyzés

    Az eredetileg támogatott, de nem támogatott (eltávolított) API-k egy későbbi verzióban várhatóan nem lesznek újra támogatottak egy még későbbi verzióban.

Példák az attribútumok működésére és az általuk előállított diagnosztikai adatokra

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

Jelentett figyelmeztetések kezelése

A diagnosztika kezelésének ajánlott módja annak biztosítása, hogy csak platformspecifikus API-kat hívjon meg, amikor egy megfelelő platformon fut. Az alábbiakban a figyelmeztetések kezelésére használható lehetőségeket találja; válassza ki a helyzetének leginkább megfelelőt:

  • Őrizd meg a hívást. Ezt úgy érheti el, hogy futtatáskor feltételesen meghívja a kódot. Ellenőrizze, hogy a kívánt Platform módon fut-e a platformellenőrzési módszerek egyikével, például OperatingSystem.Is<Platform>() vagy OperatingSystem.Is<Platform>VersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0). Példa.

  • A hívási webhely megjelölése platformspecifikusként. Dönthet úgy is, hogy a saját API-jait platformspecifikusként jelöli meg, így hatékonyan továbbítja a követelményeket a hívóknak. Jelölje meg a tartalmazó metódust vagy típust vagy a teljes szerelvényt ugyanazokkal az attribútumokkal, mint a hivatkozott platformfüggő hívás. Példák.

  • Állítsd be a hívási webhelyet platformellenőrzéssel. Ha nem szeretné a további if utasítások többletterhelését futásidőben elvégezni, használja a következőt Debug.Assert(Boolean): . Példa.

  • Törölje a kódot. Általában nem az, amit szeretne, mert ez azt jelenti, hogy elveszíti a pontosságot, amikor a kódot Windows felhasználók használják. Platformfüggetlen alternatíva esetén érdemesebb ezt platformspecifikus API-kkal használni.

  • A figyelmeztetés mellőzése. A figyelmeztetést egyszerűen letilthatja egy EditorConfig bejegyzéssel vagy #pragma warning disable CA1416. Ennek a lehetőségnek azonban végső megoldásnak kell lennie platformspecifikus API-k használatakor.

    Tipp

    Ha az előfordító irányelvekkel letiltja a #pragma figyelmeztetéseket, a megcélzott azonosítók megkülönböztetik a kis- és nagybetűket. Például ca1416 nem tiltaná le a CA1416 figyelmeztetést.

Platformspecifikus API-k őrzési módszerekkel

A guard metódus platformnevének meg kell egyeznie a hívó platformtól függő API-platform nevével. Ha a hívó API platformsztringje tartalmazza a verziót:

  • Az attribútum esetében a [SupportedOSPlatform("platformVersion")] guard metódusplatformnak version nagyobbnak vagy egyenlőnek kell lennie, mint a hívó platformé Version.

  • Az attribútum esetében a [UnsupportedOSPlatform("platformVersion")] guard metódus platformjának version kisebbnek vagy egyenlőnek kell lennie, mint a hívó 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
        }
    }
    
  • Ha meg kell őriznie a célkódokat netstandard , vagy netcoreapp ha az új OperatingSystem API-k nem érhetők el, az RuntimeInformation.IsOSPlatform API használható, és az elemző figyelembe fogja venni. Ez azonban nem olyan optimalizált, mint az új API-k.OperatingSystem Ha a struktúra nem támogatja a OSPlatform platformot, meghívhatja OSPlatform.Create(String) és átadhatja a platform nevét, amelyet az elemző is tiszteletben tart.

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

Api-k megjegyzésekkel való ellátása platformőr-attribútumokkal, és egyéni védőként való használata

Ahogy korábban láthattuk, az elemző felismeri a platformőr statikus metódusokat a OperatingSystem típusban, például OperatingSystem.IsWindowsa .RuntimeInformation.IsOSPlatform Előfordulhat azonban, hogy gyorsítótárazni szeretné a védőeredményt egy mezőben, és újra fel szeretné használni, vagy egyéni védelmi módszereket szeretne használni a platform ellenőrzéséhez. Az elemzőnek egyéni védőként kell felismernie az ilyen API-kat, és nem szabad figyelmeztetnie az általuk védett API-kat. A védőattribútumokat a .NET 6-ban vezettük be, hogy támogassa ezt a forgatókönyvet:

Ezek az attribútumok tartalmazhatnak verziószámot is. Többször is alkalmazhatók több platform őrzésére, és mező, tulajdonság vagy metódus megjegyzésekkel való ellátásához használhatók.

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

Híváswebhely megjelölése platformspecifikusként

A platformneveknek meg kell egyeznie a hívó platformtól függő API-val. Ha a platform sztringje tartalmaz verziót:

  • Az attribútum esetében a [SupportedOSPlatform("platformVersion")] hívási hely platformjának version nagyobbnak vagy egyenlőnek kell lennie, mint a hívóplatformé Version

  • Az attribútum esetében a [UnsupportedOSPlatform("platformVersion")] hívási hely platformjának version kisebbnek vagy egyenlőnek kell lennie, mint a hívóplatformé 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();
    }
    

A hívási hely érvényesítése platformellenőrzéssel

A platformőr példáiban használt összes feltételes ellenőrzés használható feltételként Debug.Assert(Boolean)is.

// An API supported only on Linux.
[SupportedOSPlatform("linux")]
public void LinuxOnlyApi() { }

public void Caller()
{
    Debug.Assert(OperatingSystem.IsLinux());

    LinuxOnlyApi(); // will not warn
}

Lásd még