CA1416: Platformkompatibilitás ellenőrzése

Tulajdonság Érték
Szabályazonosító CA1416
Cím Platformkompatibilitás ellenőrzése
Kategória Együttműködési lehetőség
A javítás kompatibilitástörő vagy nem törik Nem törés
Alapértelmezés szerint engedélyezve a .NET 8-ban Figyelmeztetésként

Ok

A szabálysértések akkor jelennek meg, ha egy platformspecifikus API-t használnak egy másik platform kontextusában, vagy ha a platform nincs ellenőrizve (platformsemleges). A szabálysértések akkor is jelentkeznek, ha a projekt célplatformján nem támogatott API-t használnak.

Ez a szabály alapértelmezés szerint csak a .NET 5 vagy újabb verziót megcélzott projektek esetében engedélyezett. Más keretrendszereket célzó projektek esetében azonban engedélyezheti.

Szabály leírása

A .NET 5 új attribútumokat adott hozzá, SupportedOSPlatformAttribute és UnsupportedOSPlatformAttributea platformspecifikus API-k megjegyzéseihez. Mindkét attribútum példányosítható verziószámmal vagy anélkül a platformnév részeként. A különböző platformokon többször is alkalmazhatók.

  • A nem módosított API-k minden operációsrendszer-platformon működnek.
  • A megjelölt [SupportedOSPlatform("platformName")] API-k csak a megadott operációsrendszer-platformokon hordozhatónak minősülnek. Ha a platform egy másik platform részhalmaza, az attribútum azt jelenti, hogy a platform is támogatott.
  • A megjelölt [UnsupportedOSPlatform("platformName")] API-k a megadott operációsrendszer-platformokon nem támogatottnak minősülnek. Ha a platform egy másik platform részhalmaza, az attribútum azt jelenti, hogy a platform szintén nem támogatott.

Egyetlen API-n kombinálhat [SupportedOSPlatform] és [UnsupportedOSPlatform] attribútumokat. Ebben az esetben a következő szabályok érvényesek:

  • Lista engedélyezése. 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. A lista rendelkezhet [UnsupportedOSPlatform] ugyanahhoz a platformhoz tartozó attribútummal, de csak magasabb verzióval, amely azt jelzi, hogy az API el lett távolítva az adott verzióból.
  • Megtagadási 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 csak magasabb verzióval, ami azt jelzi, hogy az API támogatott az adott verzió óta.
  • Inkonzisztens lista. Ha egyes platformok legalacsonyabb verziója, [SupportedOSPlatform] de [UnsupportedOSPlatform] más platformok esetében ez a kombináció inkonzisztensnek minősül. A rendszer figyelmen kívül hagy néhány megjegyzést az API-n. A jövőben bevezethetünk egy elemzőt, amely inkonzisztencia esetén figyelmeztetést ad elő.

Ha egy másik platform környezetéből éri el az ezekkel az attribútumokkal jegyzett API-t, ca1416-szabálysértéseket láthat.

TFM-célplatformok

Az elemző nem ellenőrzi a cél-keretrendszer-moniker (TFM) célplatformokat az MSBuild tulajdonságokból, például <TargetFramework> vagy <TargetFrameworks>. Ha a TFM rendelkezik célplatformmal, a .NET SDK egy attribútumot injektál SupportedOSPlatform a célplatform nevével a AssemblyInfo.cs fájlba, amelyet az elemző használ. Ha például a TFM aznet5.0-windows10.0.19041, az SDK az attribútumot a AssemblyInfo.cs fájlba injektálja[assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")], és a teljes szerelvény csak Windows-nak minősül. Ezért a csak a 7.0-s vagy újabb verziójú Windows API-k meghívása nem okoz figyelmeztetést a projektben.

Feljegyzés

Ha a AssemblyInfo.cs fájlgenerálás le van tiltva a projektben (azaz a <GenerateAssemblyInfo> tulajdonság falseértéke), a szükséges szerelvényszintű SupportedOSPlatform attribútumot az SDK nem tudja hozzáadni. Ebben az esetben a platformspecifikus API-k használatára vonatkozó figyelmeztetések akkor is megjelenhetnek, ha 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.

Megsértése

  • Ha olyan API-t ér el, amely csak egy adott platformon ([SupportedOSPlatform("platformName")]) érhető el más platformokon elérhető kódból, a következő szabálysértést fogja tapasztalni: Az "API" támogatott a "platformNév" szolgáltatásban.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    // API is supported on Windows, iOS from version 14.0, and MacCatalyst from version 14.0.
    [SupportedOSPlatform("windows")]
    [SupportedOSPlatform("ios14.0")] // MacCatalyst is a superset of iOS, therefore it's also supported.
    public void SupportedOnWindowsIos14AndMacCatalyst14() { }
    
    public void Caller()
    {
        LinuxOnlyApi(); // This call site is reachable on all platforms. 'LinuxOnlyApi()' is only supported on: 'linux'
    
        SupportedOnWindowsIos14AndMacCatalyst14(); // This call site is reachable on all platforms. 'SupportedOnWindowsIos14AndMacCatalyst14()'
                                                   // is only supported on: 'windows', 'ios' 14.0 and later, 'MacCatalyst' 14.0 and later.
    }
    

    Feljegyzés

    A szabálysértés csak akkor fordul elő, ha a projekt nem a támogatott platformot (net5.0-differentPlatform) célozza. Ez a többcélú projektekre is vonatkozik. Nem történik szabálysértés, ha a projekt a megadott platformra (net5.0-platformName) irányul, és a AssemblyInfo.cs fájllétrehozás engedélyezve van a projekt számára.

  • A nem támogatott platformot célzó környezetből hozzárendelt [UnsupportedOSPlatform("platformName")] API-k elérése szabálysértést okozhat: az "API" nem támogatott a platformnéven.

    // An API not supported on Android but supported on all other platforms.
    [UnsupportedOSPlatform("android")]
    public void DoesNotWorkOnAndroid() { }
    
    // An API was unsupported on Windows until version 10.0.18362.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void StartedWindowsSupportFromCertainVersion() { }
    
    public void Caller()
    {
        DoesNotWorkOnAndroid(); // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'
    
        StartedWindowsSupportFromCertainVersion(); // This call site is reachable on all platforms. 'StartedWindowsSupportFromCertainVersion()' is unsupported on: 'windows' 10.0.18362 and before
    }
    

Feljegyzés

Ha olyan alkalmazást készít, amely nem a nem támogatott platformot célozza meg, akkor nem fog megsérteni. A szabálysértés csak a következő esetekben fordul elő:

  • A projekt a nem támogatottnak tulajdonított platformot célozza meg.

  • Ez platformName az alapértelmezett MSBuild <SupportedPlatform> elemcsoport része.

  • platformName manuálisan szerepel az MSBuild <SupportedPlatform> elemek csoportjában.

    <ItemGroup>
        <SupportedPlatform Include="platformName" />
    </ItemGroup>
    

Szabálysértések kijavítása

A szabálysértések kezelésének ajánlott módja annak biztosítása, hogy csak platformspecifikus API-kat hívjon meg, amikor megfelelő platformon fut. Ezt úgy érheti el, hogy kizárja a kódot a buildelési időpontból #if , és több célzást alkalmaz, vagy feltételesen meghívja a kódot futásidőben. Az elemző felismeri a platformőröket az osztályban és System.Runtime.InteropServices.RuntimeInformation.IsOSPlatforma OperatingSystem .

  • A szabálysértések elhárításához használja a híváswebhelyet a szabványos platformőrző módszerekkel vagy az egyéni védő API-kkal vagy a SupportedOSPlatformGuardAttributeUnsupportedOSPlatformGuardAttribute.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    // API is supported on Windows, iOS from version 14.0, and MacCatalyst from version 14.0.
    [SupportedOSPlatform("windows")]
    [SupportedOSPlatform("ios14.0")] // MacCatalyst is a superset of iOS, therefore it's also supported.
    public void SupportedOnWindowsIos14AndMacCatalyst14() { }
    
    public void Caller()
    {
        LinuxOnlyApi(); // This call site is reachable on all platforms. 'LinuxOnlyApi()' is only supported on: 'linux'.
    
        SupportedOnWindowsIos14AndMacCatalyst14(); // This call site is reachable on all platforms. 'SupportedOnWindowsIos14AndMacCatalyst14()'
                                                   // is only supported on: 'windows', 'ios' 14.0 and later, 'MacCatalyst' 14.0 and later.
    }
    
    [SupportedOSPlatformGuard("windows")]  // The platform guard attributes used
    [SupportedOSPlatformGuard("ios14.0")]
    private readonly bool _isWindowOrIOS14 = OperatingSystem.IsWindows() || OperatingSystem.IsIOSVersionAtLeast(14);
    
    // The warnings are avoided using platform guard methods.
    public void Caller()
    {
        if (OperatingSystem.IsLinux()) // standard guard examples
        {
            LinuxOnlyApi(); // no diagnostic
        }
    
        if (OperatingSystem.IsIOSVersionAtLeast(14))
        {
            SupportedOnWindowsAndIos14(); // no diagnostic
        }
    
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            SupportedOnWindowsAndIos14(); // no diagnostic
        }
    
        if (_isWindowOrMacOS14) // custom guard example
        {
            SupportedOnWindowsAndIos14(); // no diagnostic
        }
    }
    
    // An API not supported on Android but supported on all other platforms.
    [UnsupportedOSPlatform("android")]
    public void DoesNotWorkOnAndroid() { }
    
    // An API was unsupported on Windows until version 10.0.18362.
    // The API is considered supported everywhere else without constraints.
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void StartedWindowsSupportFromCertainVersion();
    
    public void Caller()
    {
        DoesNotWorkOnAndroid(); // This call site is reachable on all platforms.'DoesNotWorkOnAndroid()' is unsupported on: 'android'
    
        StartedWindowsSupportFromCertainVersion(); // This call site is reachable on all platforms. 'StartedWindowsSupportFromCertainVersion()' is unsupported on: 'windows' 10.0.18362 and before.
    }
    
    [UnsupportedOSPlatformGuard("android")] // The platform guard attribute
    bool IsNotAndroid => !OperatingSystem.IsAndroid();
    
    public void Caller()
    {
        if (!OperatingSystem.IsAndroid()) // using standard guard methods
        {
            DoesNotWorkOnAndroid(); // no diagnostic
        }
    
        // Use the && and || logical operators to guard combined attributes.
        if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(10, 0, 18362))
        {
            StartedWindowsSupportFromCertainVersion(); // no diagnostic
        }
    
        if (IsNotAndroid) // custom guard example
        {
            DoesNotWorkOnAndroid(); // no diagnostic
        }
    }
    
  • Az elemző emellett a kód nem támogatott platformokon való elérésének megakadályozására szolgáló eszközként is tiszteli System.Diagnostics.Debug.Assert . A használat Debug.Assert lehetővé teszi az ellenőrzés kivágását a kiadási buildek közül, ha szükséges.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    public void Caller()
    {
        Debug.Assert(OperatingSystem.IsLinux());
    
        LinuxOnlyApi(); // No diagnostic
    }
    
  • Dönthet úgy, hogy saját API-jait platformspecifikusként jelöli meg, és hatékonyan továbbítja a hívóinak a követelményeket. Platformattribútumokat az alábbi API-k bármelyikére alkalmazhat:

    • Típusok
    • Tagok (metódusok, mezők, tulajdonságok és események)
    • Szerelvények
    [SupportedOSPlatform("windows")]
    [SupportedOSPlatform("ios14.0")]
    public void SupportedOnWindowsAndIos14() { }
    
    [SupportedOSPlatform("ios15.0")] // call site version should be equal to or higher than the API version
    public void Caller()
    {
        SupportedOnWindowsAndIos14(); // No diagnostics
    }
    
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void StartedWindowsSupportFromCertainVersion();
    
    [UnsupportedOSPlatform("windows")]
    [SupportedOSPlatform("windows10.0.18362")]
    public void Caller()
    {
        StartedWindowsSupportFromCertainVersion(); // No diagnostics
    }
    
  • Szerelvényszintű vagy típusszintű attribútum alkalmazásakor a rendszer platformspecifikusnak tekinti a szerelvényen vagy típuson belüli összes tagot.

    [assembly:SupportedOSPlatform("windows")]
    public namespace ns
    {
        public class Sample
        {
            public void SupportedOnWindows() { }
    
            public void Caller()
            {
                SupportedOnWindows(); // No diagnostic as call site and calling method both windows only
            }
        }
    }
    

Mikor kell letiltani a figyelmeztetéseket?

Nem ajánlott platformspecifikus API-kra hivatkozni megfelelő platformkörnyezet vagy védőkörnyezet nélkül. Ezeket a diagnosztikákat azonban letilthatja a NoWarn fordítójelölőjével #pragma vagy a szabály súlyosságának none .editorconfig fájlban való beállításával.

[SupportedOSPlatform("linux")]
public void LinuxOnlyApi() { }

public void Caller()
{
#pragma warning disable CA1416
    LinuxOnlyApi();
#pragma warning restore CA1416
}

Kód konfigurálása elemzéshez

Az elemző alapértelmezés szerint csak a .NET 5 vagy újabb verziót megcélzó és 5 vagy újabb AnalysisLevelet használó projektek esetében engedélyezett. Az alábbi kulcs-érték párok a projekt .editorconfig fájljához való hozzáadásával engedélyezheti a cél-keretrendszerek net5.0 esetében:

dotnet_code_quality.enable_platform_analyzer_on_pre_net5_target = true

Lásd még