如何在运行时(例如在 Windows 或 Linux 上)检查操作系统版本,而不使用条件编译语句

如何确定 C # 代码运行在什么平台上?例如,它是运行在 Linux 还是 Windows 上,这样我就可以在运行时执行不同的代码。

我有一个 C # Windows 应用程序,我想建立的目标 Windows 和 Linux 平台。

到目前为止,我已经创建了两个指向同一组源代码文件的项目文件。然后,我使用一个称为 LINUX的项目之一的条件编译语句。

如果实际代码中存在差异,则使用条件编译语句,例如,

#if (LINUX)
' Do something
#endif

还有更好的方法吗? 我真的不想有两个项目文件。

80060 次浏览

[Editor's Note: This answer was applicable before .NET 4.7.1, or before the Windows Compatibility Pack for .NET Core was released. The current best answer is Alex Sanséau's to Stack Overflow question How to check the OS version at runtime, e.g. on Windows or Linux, without using a conditional compilation statement.]

You can detect the execution platform using System.Environment.OSVersion.Platform:

public static bool IsLinux
{
get
{
int p = (int) Environment.OSVersion.Platform;
return (p == 4) || (p == 6) || (p == 128);
}
}

From the Mono FAQ:

How to detect the execution platform

The execution platform can be detected by using the System.Environment.OSVersion.Platform value. However correctly detecting Unix platforms, in every cases, requires a little more work. The first versions of the framework (1.0 and 1.1) didn't include any PlatformID value for Unix, so Mono used the value 128. The newer framework 2.0 added Unix to the PlatformID enum but, sadly, with a different value: 4 and newer versions of .NET distinguished between Unix and macOS, introducing yet another value 6 for macOS.

This means that in order to detect properly code running on Unix platforms you must check the three values (4, 6 and 128). This ensure that the detection code will work as expected when executed on Mono CLR 1.x runtime and with both Mono and Microsoft CLR 2.x runtimes.

Use:

System.Environment.OSVersion

You can use System.Environment.OSVersion to check what kind of platform you're on at runtime.

To expand on other answers, in cases where a Linux and Windows implementation of a feature are not compatible (that is, require references to libraries only available for a specific platform), you can also use an interface and have two separate assemblies, one written and compiled on each platform, with a type that implements this interface.

Then, based on the check, use Assembly.Load() to load only the right assembly (and its platform-specific dependency), reflection to find your type in the assembly, and Activator.CreateInstance() to get an instance of the type that you can then work with normally.

I found this recommendation on one of Microsoft's blogs:

We recommend you to use RuntimeInformation.IsOSPlatform() for platform checks.

Reference: Announcing the Windows Compatibility Pack for .NET Core

IsOSPlatform() takes an argument of types OSPlatform which has three values by default: Windows, Linux and OSX. It can be used as follow:

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// Do something
}

The API is part of .NET Standard 2.0, and therefore available in .NET Core 2.0 and .NET Framework 4.7.1.

One more option is to use Process to call a shell script to get the uname, as follows:

Process p = new Process {
StartInfo = {
UseShellExecute        = false,
RedirectStandardOutput = true,
FileName               = "uname",
Arguments              = "-s"
}
};
p.Start();
string uname = p.StandardOutput.ReadToEnd().Trim();


if (uname == "Darwin") {
// OS X
} else {
// ...
}

There isn't any such method, but you can use this method that checks it conditionally:

    public static OSPlatform GetOperatingSystem()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return OSPlatform.OSX;
}


if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return OSPlatform.Linux;
}


if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return OSPlatform.Windows;
}


throw new Exception("Cannot determine operating system!");
}
OperatingSystem os = new OperatingSystem(System.Environment.OSVersion.Platform, new Version());
Console.WriteLine(os.ToString());

Built-in static method: System.Runtime.Serialization.OperatingSystem.IsLinux().

.NET 5+ has the OperatingSystem class, so now you can just:

if (OperatingSystem.IsWindows())
DoSomething();