CA1416: Ověření kompatibility platformy

Vlastnost Hodnota
ID pravidla CA1416
Název Ověřit kompatibilitu platformy
Kategorie Vzájemná funkční spolupráce
Oprava způsobující chybu nebo chybu způsobující chybu Nenarušující
Povoleno ve výchozím nastavení v .NET 8 Jako upozornění

Příčina

Porušení se hlásí, pokud se rozhraní API specifické pro platformu používá v kontextu jiné platformy nebo pokud není ověřená (platforma neutrální). Porušení se hlásí také v případě, že se používá rozhraní API, které není podporováno pro cílovou platformu projektu.

Toto pravidlo je ve výchozím nastavení povolené jenom pro projekty, které cílí na .NET 5 nebo novější. Můžete ho ale povolit pro projekty, které cílí na jiné architektury.

Popis pravidla

Rozhraní .NET 5 přidalo nové atributy SupportedOSPlatformAttribute a UnsupportedOSPlatformAttributepro přidávání poznámek rozhraní API specifických pro platformu. V rámci názvu platformy je možné vytvořit instanci obou atributů s čísly verzí nebo bez. Lze je také použít vícekrát s různými platformami.

  • Neoznačené rozhraní API se považuje za funkční na všech platformách operačního systému (OS).
  • Rozhraní API označené [SupportedOSPlatform("platformName")] jako přenosné pouze na určené platformy operačního systému. Pokud je platforma podmnožinou jiné platformy, atribut znamená, že se tato platforma podporuje také.
  • Rozhraní API označené [UnsupportedOSPlatform("platformName")] jako nepodporované na zadaných platformách operačního systému se považuje za nepodporované. Pokud je platforma podmnožinou jiné platformy, atribut znamená, že tato platforma není podporována.

V jednom rozhraní API můžete kombinovat a [UnsupportedOSPlatform] atributy[SupportedOSPlatform]. V tomto případě platí následující pravidla:

  • Seznam povolených položek Pokud je nejnižší verze pro každou platformu [SupportedOSPlatform] operačního systému atributem, rozhraní API se považuje za podporované pouze uvedenými platformami a nepodporované všemi ostatními platformami. Seznam může mít atribut se stejnou [UnsupportedOSPlatform] platformou, ale pouze s vyšší verzí, která označuje, že rozhraní API je z této verze odebráno.
  • Odepřít seznam. Pokud je nejnižší verze pro každou platformu [UnsupportedOSPlatform] operačního systému atributem, rozhraní API se považuje za nepodporované pouze pro uvedené platformy a podporované všemi ostatními platformami. Seznam může mít atribut se stejnou [SupportedOSPlatform] platformou, ale pouze s vyšší verzí, která označuje, že rozhraní API je od této verze podporované.
  • Nekonzistentní seznam Pokud je [SupportedOSPlatform] nejnižší verze některých platforem, ale [UnsupportedOSPlatform] pro jiné platformy, považuje se tato kombinace za nekonzistentní. Některé poznámky v rozhraní API se ignorují. V budoucnu můžeme zavést analyzátor, který v případě nekonzistence vytvoří upozornění.

Pokud přistupujete k rozhraní API s poznámkami s těmito atributy z kontextu jiné platformy, můžete zobrazit porušení CA1416.

Cílové platformy TFM

Analyzátor nekontroluje cílové platformy monikeru (TFM) cílové platformy z vlastností NÁSTROJE MSBuild, například <TargetFramework> nebo <TargetFrameworks>. Pokud má TFM cílovou platformu, sada .NET SDK vloží SupportedOSPlatform do souboru AssemblyInfo.cs atribut s názvem cílové platformy, který analyzátor využívá. Pokud je net5.0-windows10.0.19041například TFM , sada SDK vloží [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] atribut do souboru AssemblyInfo.cs a celé sestavení se považuje pouze za Windows. Proto volání rozhraní API jen pro Windows ve verzi 7.0 nebo novější nezpůsobí žádná upozornění v projektu.

Poznámka:

Pokud je generování souboru AssemblyInfo.cs pro projekt zakázané (to znamená, že <GenerateAssemblyInfo> vlastnost je nastavena na false), nelze přidat požadovaný atribut úrovně SupportedOSPlatform sestavení sadou SDK. V takovém případě se zobrazí upozornění na využití rozhraní API specifická pro konkrétní platformu, i když na tuto platformu cílíte. Pokud chcete upozornění vyřešit, povolte generování AssemblyInfo.cs souboru nebo přidejte atribut do projektu ručně.

Porušování

  • Pokud přistupujete k rozhraní API, které je podporované jenom na zadané platformě ([SupportedOSPlatform("platformName")]) z kódu dostupného na jiných platformách, uvidíte následující porušení: "API" je podporováno na platformě PlatformName.

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

    Poznámka:

    K porušení dojde pouze v případě, že projekt nebude cílit na podporovanou platformu (net5.0-differentPlatform). To platí také pro projekty s více cíli. K žádnému porušení nedojde, pokud projekt cílí na zadanou platformu (net5.0-platformName) aAssemblyInfo.cs generování souborů je pro projekt povolené.

  • Přístup k rozhraní API, které je přiřazeno [UnsupportedOSPlatform("platformName")] z kontextu, který cílí na nepodporovanou platformu, může způsobit porušení: "API" není podporováno na platformě PlatformName.

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

Poznámka:

Pokud vytváříte aplikaci, která necílí na nepodporovanou platformu, nebudete dostávat žádná porušení. K porušení dojde pouze v následujících případech:

  • Projekt cílí na platformu, která je přiřazená jako nepodporovaná.

  • Je platformName součástí výchozí skupiny položek NÁSTROJE MSBuild <SupportedPlatform> .

  • platformName je ručně zahrnutý do skupiny položek nástroje MSBuild <SupportedPlatform> .

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

Jak opravit porušení

Doporučeným způsobem řešení porušení je zajistit, abyste při spouštění na příslušné platformě volali pouze rozhraní API specifická pro danou platformu. Toho dosáhnete tak, že kód v době sestavení vyloučíte pomocí #if a cílení na více verzí, nebo podmíněným voláním kódu za běhu. Analyzátor rozpozná ochranu platformy ve OperatingSystem třídě a System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform.

  • Potlačte porušení tím, že obklopíte web volání standardními metodami ochrany platformy nebo vlastními rozhraními API ochrany ochrany anotací s SupportedOSPlatformGuardAttribute nebo UnsupportedOSPlatformGuardAttribute.

    // 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
        }
    }
    
  • Analyzátor také System.Diagnostics.Debug.Assert respektuje jako prostředek, který brání dosažení kódu na nepodporovaných platformách. Použití Debug.Assert umožňuje, aby se kontrola v případě potřeby ořízla z buildů vydaných verzí.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    public void Caller()
    {
        Debug.Assert(OperatingSystem.IsLinux());
    
        LinuxOnlyApi(); // No diagnostic
    }
    
  • Můžete se rozhodnout, že vlastní rozhraní API označíte jako specifická pro konkrétní platformu a efektivně předáte požadavky volajícím. Atributy platformy můžete použít na libovolná z následujících rozhraní API:

    • Typy
    • Členové (metody, pole, vlastnosti a události)
    • Sestavení
    [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
    }
    
  • Při použití atributu na úrovni sestavení nebo typu se považují všechny členy v rámci sestavení nebo typu za specifické pro platformu.

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

Kdy potlačit upozornění

Odkazování na rozhraní API specifická pro platformu bez správného kontextu platformy nebo ochrany se nedoporučuje. Tuto diagnostiku však můžete potlačit příznakem #pragma kompilátoru NoWarn nebo nastavením závažnosti pravidla na none soubor .editorconfig .

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

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

Konfigurace kódu pro analýzu

Analyzátor je ve výchozím nastavení povolený jenom pro projekty, které cílí na .NET 5 nebo novější a mají hodnotu AnalysisLevel 5 nebo vyšší. Můžete ji povolit pro cílové architektury nižší než net5.0 přidáním následujícího páru klíč-hodnota do souboru .editorconfig v projektu:

dotnet_code_quality.enable_platform_analyzer_on_pre_net5_target = true

Viz také