-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Related to #44922
Background and Motivation
The CA1416 Platform Compatibility analyzer already recognizes platform guards using the methods on OperatingSystem
, such as OperatingSystem.IsWindows
and OperatingSystem.IsWindowsVersionAtLeast
. However, the analyzer does not recognize other guard methods like a field, property or helper methods that assert platform guards. Expanding this support involves creating new attributes that indicate that an API asserts platform checks the same way the APIs on OperatingSystem
do.
Proposed API
namespace System.Runtime.Versioning
{
// Existing base type for all platform-specific attributes.
public abstract class OSPlatformAttribute : Attribute
{
private protected OSPlatformAttribute(string platformName);
public string PlatformName { get; }
}
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Enum, AllowMultiple = true, Inherited = false)]
+ public sealed class SupportedOSPlatformGuardAttribute : OSPlatformAttribute
+ {
+ public SupportedOSPlatformGuardAttribute(string platformName) ;
+ }
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Enum, AllowMultiple = true, Inherited = false)]
+ public sealed class UnsupportedOSPlatformGuardAttribute : OSPlatformAttribute
+ {
+ public UnsupportedOSPlatformGuardAttribute(string platformName) ;
+ }
}
Usage Examples
One example is in Thread
, there is an internal field for IsThreadStartSupported
that indicates whether or not the current platform supports calls to Thread.Start
, which is not supported on browser
. So in this [UnsupportedOSPlatformGuard]
attributes can be used for this field. And the analyzer will recognize it as a platform guard.
#if !TARGET_BROWSER
[UnsupportedOSPlatformGuard("browser")] // The platform guard atribute
internal const bool IsThreadStartSupported = true;
#endif
// Usage example
protected internal override void QueueTask(Task task)
{
if (Thread.IsThreadStartSupported) // This will be evaluated same as `!OperatingSystem.IsBrowser()`
{
new Thread(s_longRunningThreadWork)
{
IsBackground = true,
Name = ".NET Long Running Task"
}.UnsafeStart(task); // Call unsupported on browser APIs safely (without the attribute it would warn here)
}
}
Additionally, it's expected that projects will commonly create helper methods that wrap around the platform-specific API
calls. The platform being guarded using these attributes can be versioned.
[SupportedOSPlatformGuard("windows10.0")]
public bool IsWindows10OrAbove()
{
return OperatingSystem.IsWindowsVersionAtLeast(10);
}
[SupportedOSPlatform("windows10.0")]
public bool Windows10OnlyAPI() { }
void Sample ()
{
if (IsWindows10OrAbove()) // work same as OperatingSystem.IsWindowsVersionAtLeast(10)
{
Windows10OnlyAPI();
}
}
For guarding multiple platforms need to apply the attribute for each platform
class Test
{
[SupportedOSPlatformGuard(""linux"")]
[SupportedOSPlatformGuard(""macOS"")]
[SupportedOSPlatformGuard(""Windows"")]
private readonly bool _http3Enabled = OperatingSystem.IsLinux() || OperatingSystem.IsWindows() || OperatingSystem.IsMacOS();
void M1()
{
if (_http3Enabled)
{
ApiWorkOnWindowsLinuxMac(); // Not warn
}
else
{
ApiWorkOnWindowsLinuxMac(); // Warns
}
}
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macos")]
void ApiWorkOnWindowsLinuxMac() { }
}