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 8 | 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 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 } }
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
- CA1422: Platformcompatibiliteit valideren
- Platformcompatibiliteitsanalyse (conceptueel)
- Aantekeningen maken bij platformspecifieke API's en het gebruik ervan detecteren
- Aantekeningen toevoegen aan API's als niet-ondersteund op specifieke platforms
- Namen van doelframeworks in .NET 5
- Interoperabiliteitsregels