Delen via


CA1416: Platformcompatibiliteit valideren

Eigenschappen Weergegeven als
Regel-id CA1416
Titel Platformcompatibiliteit valideren
Categorie Interoperabiliteit
Oplossing is brekend of niet-brekend Niet-brekend
Standaard ingeschakeld in .NET 9 Als waarschuwing

Oorzaak

Schendingen worden gerapporteerd als een platformspecifieke API wordt gebruikt in de context van een ander platform of als het platform niet is geverifieerd (platformneutraal). Schendingen worden ook gerapporteerd als een API die niet wordt ondersteund voor het doelplatform van het project wordt gebruikt.

Deze regel is standaard alleen ingeschakeld voor projecten die gericht zijn op .NET 5 of hoger. U kunt deze echter inschakelen voor projecten die zijn gericht op andere frameworks.

Beschrijving van regel

.NET 5 heeft nieuwe kenmerken SupportedOSPlatformAttribute toegevoegd en UnsupportedOSPlatformAttribute, om aantekeningen te maken bij platformspecifieke API's. Beide kenmerken kunnen worden geïnstantieerd met of zonder versienummers als onderdeel van de platformnaam. Ze kunnen ook meerdere keren worden toegepast met verschillende platforms.

  • Een niet-geannoteerde API wordt beschouwd als werken op alle besturingssysteemplatforms (OS).
  • Een API die is gemarkeerd met [SupportedOSPlatform("platformName")] , wordt beschouwd als alleen draagbaar voor de opgegeven besturingssysteemplatformen. Als het platform een subset van een ander platform is, impliceert het kenmerk dat dat platform ook wordt ondersteund.
  • Een API die is gemarkeerd met [UnsupportedOSPlatform("platformName")] , wordt beschouwd als niet ondersteund op de opgegeven besturingssysteemplatforms. Als het platform een subset van een ander platform is, impliceert het kenmerk dat dat platform ook niet wordt ondersteund.

U kunt kenmerken en [SupportedOSPlatform] [UnsupportedOSPlatform] combineren in één API. In dit geval zijn de volgende regels van toepassing:

  • Acceptatielijst. 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 lijst kan een [UnsupportedOSPlatform] kenmerk hebben met hetzelfde platform, maar alleen met een hogere versie, wat aangeeft dat de API uit die versie wordt verwijderd.
  • Lijst weigeren. 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 [SupportedOSPlatform] kenmerk hebben met hetzelfde platform, maar alleen met een hogere versie, wat aangeeft dat de API wordt ondersteund sinds die versie.
  • Inconsistente lijst. Als de laagste versie voor sommige platforms maar [UnsupportedOSPlatform] voor andere platforms is[SupportedOSPlatform], wordt deze combinatie als inconsistent beschouwd. Sommige aantekeningen in de API worden genegeerd. In de toekomst kunnen we een analyse introduceren die een waarschuwing produceert in geval van inconsistentie.

Als u toegang krijgt tot een API met aantekeningen met deze kenmerken vanuit de context van een ander platform, kunt u schendingen van CA1416 zien.

TFM-doelplatforms

De analyzer controleert geen doelframework moniker (TFM) doelplatforms van MSBuild-eigenschappen, zoals <TargetFramework> of <TargetFrameworks>. Als de TFM een doelplatform heeft, injecteert de .NET SDK een SupportedOSPlatform kenmerk met de doelplatformnaam in het AssemblyInfo.cs-bestand , dat door de analyse wordt gebruikt. Als de TFM bijvoorbeeld is net5.0-windows10.0.19041, injecteert de SDK 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 de SDK. 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.

Schendingen

  • Als u toegang krijgt tot een API die alleen wordt ondersteund op een opgegeven platform ([SupportedOSPlatform("platformName")]) vanuit code die bereikbaar is op andere platforms, ziet u de volgende schending: 'API' wordt ondersteund op '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.
    }
    

    Notitie

    Er treedt alleen een schending op als het project niet is gericht op het ondersteunde platform (net5.0-differentPlatform). Dit geldt ook voor projecten met meerdere doelgroepen. Er treedt geen schending op als het project is gericht op het opgegeven platform (net5.0-platformName) en de AssemblyInfo.cs bestandsgeneratie is ingeschakeld voor het project.

  • Toegang tot een API die is toegeschreven aan [UnsupportedOSPlatform("platformName")] een context die is gericht op het niet-ondersteunde platform, kan een schending opleveren: 'API' wordt niet ondersteund op '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
    }
    

Notitie

Als u een app bouwt die niet is gericht op het niet-ondersteunde platform, krijgt u geen schendingen. Een schending treedt alleen op in de volgende gevallen:

  • Het project is gericht op het platform dat wordt toegeschreven als niet-ondersteund.

  • De platformName is opgenomen in de standaardGROEP MSBuild-items <SupportedPlatform> .

  • platformName is handmatig opgenomen in de MSBuild-itemsgroep <SupportedPlatform> .

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

Schendingen oplossen

De aanbevolen manier om schendingen aan te pakken, is ervoor te zorgen dat u alleen platformspecifieke API's aanroept wanneer u op een geschikt platform wordt uitgevoerd. U kunt dit bereiken door de code tijdens het bouwen uit te sluiten met behulp van #if en meerdere doelen, of door de code voorwaardelijk aan te roepen tijdens runtime. De analyzer herkent het platform bewaakt in de OperatingSystem klasse en System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform.

  • Onderdrukking van schendingen door de oproepsite te omringen met de standaardplatformbeveiligingsmethoden of aangepaste guard-API's met aantekeningen of SupportedOSPlatformGuardAttribute 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
        }
    }
    
  • De analyse respecteert System.Diagnostics.Debug.Assert ook als een middel om te voorkomen dat de code wordt bereikt op niet-ondersteunde platforms. Als Debug.Assert u deze optie gebruikt, kan de controle desgewenst worden afgekapt uit de releaseversies.

    // An API supported only on Linux.
    [SupportedOSPlatform("linux")]
    public void LinuxOnlyApi() { }
    
    public void Caller()
    {
        Debug.Assert(OperatingSystem.IsLinux());
    
        LinuxOnlyApi(); // No diagnostic
    }
    
  • U kunt ervoor kiezen om uw eigen API's als platformspecifiek te markeren en de vereisten effectief door te sturen naar uw bellers. U kunt platformkenmerken toepassen op een van de volgende API's:

    • Typen
    • Leden (methoden, velden, eigenschappen en gebeurtenissen)
    • Assembly's
    [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
    }
    
  • Wanneer een kenmerk op assembly- of typeniveau wordt toegepast, worden alle leden binnen de assembly of het type beschouwd als platformspecifiek.

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

Wanneer waarschuwingen onderdrukken

Het wordt afgeraden om te verwijzen naar platformspecifieke API's zonder een juiste platformcontext of beveiliging. U kunt deze diagnostische gegevens echter onderdrukken met behulp van #pragma de vlag van de NoWarn-compiler of door de ernst van de regel in te none stellen in een .editorconfig-bestand .

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

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

Code configureren om te analyseren

De analyse is standaard alleen ingeschakeld voor projecten die gericht zijn op .NET 5 of hoger en een AnalysisLevel van 5 of hoger hebben. U kunt deze inschakelen voor doelframeworks die lager zijn dan net5.0 door het volgende sleutel-waardepaar toe te voegen aan een .editorconfig-bestand in uw project:

dotnet_code_quality.enable_platform_analyzer_on_pre_net5_target = true

Zie ook