CA1416: Verifiera plattformskompatibilitet

Property Värde
Regel-ID CA1416
Title Verifiera plattformskompatibilitet
Kategori Samverkan
Korrigeringen är icke-bakåtkompatibel Icke-icke-bryta
Aktiverad som standard i .NET 8 Som varning

Orsak

Överträdelser rapporteras om ett plattformsspecifikt API används i kontexten för en annan plattform eller om plattformen inte verifieras (plattformsneutral). Överträdelser rapporteras också om ett API som inte stöds för projektets målplattform används.

Den här regeln är endast aktiverad som standard för projekt som är avsedda för .NET 5 eller senare. Du kan dock aktivera den för projekt som riktar in sig på andra ramverk.

Regelbeskrivning

.NET 5 har lagt till nya attribut SupportedOSPlatformAttribute och UnsupportedOSPlatformAttribute, för att kommentera plattformsspecifika API:er. Båda attributen kan instansieras med eller utan versionsnummer som en del av plattformsnamnet. De kan också användas flera gånger med olika plattformar.

  • Ett icke-kommenterat API anses fungera på alla operativsystemplattformar (OS).
  • Ett API som markerats med [SupportedOSPlatform("platformName")] anses endast vara portabelt till de angivna operativsystemplattformarna. Om plattformen är en delmängd av en annan plattform innebär attributet att den plattformen också stöds.
  • Ett API som har markerats med [UnsupportedOSPlatform("platformName")] anses inte ha stöd för de angivna OS-plattformarna. Om plattformen är en delmängd av en annan plattform innebär attributet att plattformen inte heller stöds.

Du kan kombinera [SupportedOSPlatform] och [UnsupportedOSPlatform] attribut på ett enda API. I det här fallet gäller följande regler:

  • Tillåt lista. Om den lägsta versionen för varje OS-plattform är ett [SupportedOSPlatform] attribut anses API:et endast stödjas av de listade plattformarna och stöds inte av alla andra plattformar. Listan kan ha ett [UnsupportedOSPlatform] attribut med samma plattform, men bara med en högre version, vilket anger att API:et tas bort från den versionen.
  • Neka lista. Om den lägsta versionen för varje OS-plattform är ett [UnsupportedOSPlatform] attribut anses API:et endast inte stödjas av de listade plattformarna och stöds av alla andra plattformar. Listan kan ha ett [SupportedOSPlatform] attribut med samma plattform, men bara med en högre version, vilket anger att API:et stöds sedan den versionen.
  • Inkonsekvent lista. Om den lägsta versionen för vissa plattformar bara är [SupportedOSPlatform][UnsupportedOSPlatform] för andra plattformar anses den här kombinationen vara inkonsekvent. Vissa anteckningar i API:et ignoreras. I framtiden kan vi introducera en analysator som skapar en varning i händelse av inkonsekvens.

Om du har åtkomst till ett API som kommenterats med dessa attribut från kontexten för en annan plattform kan du se CA1416-överträdelser.

TFM-målplattformar

Analysatorn kontrollerar inte målplattformen för målramverk (TFM) från MSBuild-egenskaper, till exempel <TargetFramework> eller <TargetFrameworks>. Om TFM har en målplattform matar .NET SDK in ett SupportedOSPlatform attribut med målplattformsnamnet i AssemblyInfo.cs-filen, som används av analysatorn. Om TFM till exempel är net5.0-windows10.0.19041matar SDK in [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows10.0.19041")] attributet i filen AssemblyInfo.cs och hela sammansättningen anses vara endast Windows. Därför skulle det inte orsaka några varningar i projektet att anropa API:er med endast Windows som är version 7.0 eller senare.

Kommentar

Om den AssemblyInfo.cs filgenereringen är inaktiverad för projektet (dvs <GenerateAssemblyInfo> . egenskapen är inställd på false) kan det obligatoriska sammansättningsnivåattributet SupportedOSPlatform inte läggas till av SDK:t. I det här fallet kan du se varningar för en plattformsspecifik API:er-användning även om du riktar in dig på den plattformen. Lös varningarna genom att aktivera AssemblyInfo.cs filgenerering eller lägga till attributet manuellt i projektet.

Kränkningar

  • Om du får åtkomst till ett API som endast stöds på en angiven plattform ([SupportedOSPlatform("platformName")]) från kod som kan nås på andra plattformar visas följande överträdelse: "API" stöds på "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.
    }
    

    Kommentar

    En överträdelse inträffar endast om projektet inte riktar sig mot den plattform som stöds (net5.0-differentPlatform). Detta gäller även för projekt med flera mål. Ingen överträdelse inträffar om projektet riktar sig mot den angivna plattformen (net5.0-platformName) och AssemblyInfo.cs filgenerering är aktiverad för projektet.

  • Åtkomst till ett API som tillskrivs [UnsupportedOSPlatform("platformName")] från en kontext som riktar sig mot plattformen som inte stöds kan leda till en överträdelse: "API" stöds inte på "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
    }
    

Kommentar

Om du skapar en app som inte riktar sig mot plattformen som inte stöds får du inga överträdelser. En överträdelse sker endast i följande fall:

  • Projektet riktar in sig på den plattform som tillskrivs som stöds inte.

  • platformName ingår i standardgruppen MSBuild-objekt<SupportedPlatform>.

  • platformName ingår manuellt i gruppen MSBuild-objekt <SupportedPlatform> .

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

Så här åtgärdar du överträdelser

Det rekommenderade sättet att hantera överträdelser är att se till att du bara anropar plattformsspecifika API:er när du kör på en lämplig plattform. Du kan uppnå detta genom att undanta koden vid byggtiden med hjälp av #if och flera mål, eller genom att villkorligt anropa koden vid körning. Analysatorn identifierar plattformsskydden OperatingSystem i klassen och System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform.

  • Förhindra överträdelser genom att omge anropsplatsen med standardmetoderna för plattformsskydd eller anpassade skydds-API:er som kommenterats med SupportedOSPlatformGuardAttribute eller 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
        }
    }
    
  • Analysatorn respekterar System.Diagnostics.Debug.Assert också som ett sätt att förhindra att koden nås på plattformar som inte stöds. Med hjälp av Debug.Assert kan kontrollen trimmas ut från versionsversioner, om så önskas.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    public void Caller()
    {
        Debug.Assert(OperatingSystem.IsLinux());
    
        LinuxOnlyApi(); // No diagnostic
    }
    
  • Du kan välja att markera dina egna API:er som plattformsspecifika, vilket effektivt vidarebefordrar kraven till dina uppringare. Du kan använda plattformsattribut på någon av följande API:er:

    • Typer
    • Medlemmar (metoder, fält, egenskaper och händelser)
    • Sammansättningar
    [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
    }
    
  • När ett attribut på sammansättningsnivå eller typnivå tillämpas anses alla medlemmar i sammansättningen eller typen vara plattformsspecifika.

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

När du ska ignorera varningar

Att referera till plattformsspecifika API:er utan rätt plattformskontext eller skydd rekommenderas inte. Du kan dock utelämna den här diagnostiken med hjälp av #pragma eller nowarn-kompilatorflaggan, eller genom att ange regelns allvarlighetsgrad till none i en .editorconfig-fil.

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

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

Konfigurera kod för analys

Analysatorn är endast aktiverad som standard för projekt som riktar in sig på .NET 5 eller senare och har en AnalysisLevel på 5 eller högre. Du kan aktivera det för målramverk som är lägre än net5.0 genom att lägga till följande nyckel/värde-par i en .editorconfig-fil i projektet:

dotnet_code_quality.enable_platform_analyzer_on_pre_net5_target = true

Se även