-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
In .NET Core 1.x and 2.x days, we added very limited ability for customers to check which OS they were on. We originally didn't even expose Environment.OSVersion
and we built a new API RuntimeInformation.IsOSPlatform()
. The assumption was that doing OS checks is exclusively done for P/invoke or interoperating with native code, which is why RuntimeInformation
was put in System.Runtime.InteropServices
.
However, guarding calls to OS bindings or avoiding unsupported APIs in Blazor isn't really a P/invoke scenario. It's seems counterproductive to force these customers to import the System.Runtime.InteropServices
namespace.
API Proposal
Since RuntimeInformation
is a very small type today, the proposal is: don't add the API for version checks on RuntimeInformation
but instead to add them to Environment
.
Environment
was the canonical place where people have performed OS checks in the past and are most likely to look for them moving forward. RuntimeInformation
is a fairly recent type. And compared to Environment.OSVersion the RuntimeInformation type hasn't gained much adoption yet.
namespace System
{
public static partial class Environment
{
// Primary
public static bool IsOSPlatform(string platform);
public static bool IsOSPlatformVersionAtLeast(string platform, int major, int minor = 0, int build = 0, int revision = 0);
// Accelerators for platforms where versions don't make sense
public static bool IsBrowser();
public static bool IsFreeBSD();
public static bool IsLinux();
// Accelerators with version checks
public static bool IsAndroid();
public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0);
public static bool IsiOS();
public static bool IsiOSVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0);
public static bool IsmacOS();
public static bool IsmacOSVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0);
public static bool IstvOS();
public static bool IstvOSVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0);
public static bool IswatchOS();
public static bool IswatchOSVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0);
public static bool IsWindows();
public static bool IsWindowsVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0);
}
}
For the attributes, we'd like to put the core ones people are likely to apply to their own code in the same namespace as the guards, i.e. in System
. We'll leave the base type and the TargetPlatformAttribute
in System.Runtime.Versioning
.
namespace System
{
[AttributeUsage(AttributeTargets.Assembly |
AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Enum |
AttributeTargets.Event |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Module |
AttributeTargets.Property |
AttributeTargets.Struct,
AllowMultiple = true, Inherited = false)]
public sealed class SupportedOSPlatformAttribute : OSPlatformAttribute
{
public SupportedOSPlatformAttribute(string platformName);
}
[AttributeUsage(AttributeTargets.Assembly |
AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Enum |
AttributeTargets.Event |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Module |
AttributeTargets.Property |
AttributeTargets.Struct,
AllowMultiple = true, Inherited = false)]
public sealed class UnsupportedOSPlatformAttribute : OSPlatformAttribute
{
public UnsupportedOSPlatformAttribute(string platformName);
}
[AttributeUsage(AttributeTargets.Assembly |
AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Event |
AttributeTargets.Method |
AttributeTargets.Module |
AttributeTargets.Property |
AttributeTargets.Struct,
AllowMultiple=true, Inherited=false)]
public sealed class ObsoletedInOSPlatformAttribute : OSPlatformAttribute
{
public ObsoletedInPlatformAttribute(string platformName);
public ObsoletedInPlatformAttribute(string platformName, string message);
public string Message { get; }
public string Url { get; set; }
}
}
namespace System.Runtime.Versioning
{
public abstract class OSPlatformAttribute : Attribute
{
private protected OSPlatformAttribute(string platformName);
public string PlatformName { get; }
}
[AttributeUsage(AttributeTargets.Assembly,
AllowMultiple=false, Inherited=false)]
public sealed class TargetPlatformAttribute : OSPlatformAttribute
{
public TargetPlatformAttribute(string platformName);
}
}
This would remove the following APIs:
namespace System.Runtime.InteropServices
{
public static class RuntimeInformation
{
// Existing APIs
public static string FrameworkDescription { get; }
public static string OSArchitecture { get; }
public static string OSDescription { get; }
public static string ProcessArchitecture { get; }
public static string RuntimeIdentifier { get; }
public static bool IsOSPlatform(OSPlatform osPlatform);
- // APIs proposed earlier for .NET 5.0
- public static bool IsOSPlatformOrLater(string platformName);
- public static bool IsOSPlatformOrLater(OSPlatform osPlatform, int major);
- public static bool IsOSPlatformOrLater(OSPlatform osPlatform, int major, int minor);
- public static bool IsOSPlatformOrLater(OSPlatform osPlatform, int major, int minor, int build);
- public static bool IsOSPlatformOrLater(OSPlatform osPlatform, int major, int minor, int build, int revision);
- public static bool IsOSPlatformEarlierThan(string platformName);
- public static bool IsOSPlatformEarlierThan(OSPlatform osPlatform, int major);
- public static bool IsOSPlatformEarlierThan(OSPlatform osPlatform, int major, int minor);
- public static bool IsOSPlatformEarlierThan(OSPlatform osPlatform, int major, int minor, int build);
- public static bool IsOSPlatformEarlierThan(OSPlatform osPlatform, int major, int minor, int build, int revision);
}
}