我写了一个 C# 程序来检测 .NET Framework CLR 版本。
在 Ubuntu 操作系统中的运行结果:
在 Windows Vista 操作系统中的运行结果:
注意,这个程序检测的是 .NET Framework CLR 版本,而不是 .NET Framework 版本。实际上这个 Windows Vista 操作系统中安装了 .NET Framework 的以下版本:
- 2.0.50727.4016
- 3.0.30729.4037
- 3.5.30729.01
而三个版本的 .NET Framework 的 CLR 版本都是 2.0.50727。
在 Windows Server 2003 操作系统中的运行结果:
另外,Microsoft Windows SDK 中的 ClrVer.exe 的运行结果:
我们来看看源程序吧。下面是 ClrInfo.cs:
using System; using System.Text; namespace Skyiv { public class ClrInfo { static void Main() { Console.WriteLine(" OS Version: {0}", Environment.OSVersion); Console.WriteLine(" CLR Version: {0} ( {1} )", Environment.Version, RuntimeFramework.CurrentFramework); Console.WriteLine("Default Encoding: {0}", Encoding.Default); Console.WriteLine(); Console.WriteLine("Available Frameworks:"); foreach (var frame in RuntimeFramework.AvailableFrameworks) Console.WriteLine(" " + frame); } } }
下面是 RuntimeFramework.cs (该程序是从 NUnit 的源程序中的同名文件改写而来的):
using System; using System.Reflection; using System.Collections.Generic; using Microsoft.Win32; namespace Skyiv { public enum RuntimeType { Any, // Any supported runtime framework Net, // Microsoft .NET Framework NetCF, // Microsoft .NET Compact Framework SSCLI, // Microsoft Shared Source CLI Mono, // Mono } // See http://nunit.org, this class from NUnit Project's RuntimeFramework.cs // RuntimeFramework represents a particular version of a common language runtime implementation. [Serializable] public sealed class RuntimeFramework { public RuntimeType Runtime { get; private set; } public Version Version { get; private set; } public string DisplayName { get; private set; } static RuntimeFramework currentFramework; public static RuntimeFramework CurrentFramework { get { if (currentFramework == null) { var monoRuntimeType = Type.GetType("Mono.Runtime", false); var runtime = monoRuntimeType != null ? RuntimeType.Mono : RuntimeType.Net; currentFramework = new RuntimeFramework(runtime, Environment.Version); if (monoRuntimeType != null) { var method = monoRuntimeType.GetMethod("GetDisplayName", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding); if (method != null) currentFramework.DisplayName = (string)method.Invoke(null, new object[0]); } } return currentFramework; } } public static RuntimeFramework[] AvailableFrameworks { get { var frameworks = new List<RuntimeFramework>(); foreach (var framework in GetAvailableFrameworks(RuntimeType.Net)) frameworks.Add(framework); foreach (var framework in GetAvailableFrameworks(RuntimeType.Mono)) frameworks.Add(framework); return frameworks.ToArray(); } } public static bool IsMonoInstalled() { if (CurrentFramework.Runtime == RuntimeType.Mono) return true; // Don't know how to do this on linux yet, but it's not a problem since we are only supporting Mono on Linux if (Environment.OSVersion.Platform != PlatformID.Win32NT) return false; var key = Registry.LocalMachine.OpenSubKey(@"Software\Novell\Mono"); if (key == null) return false; var version = key.GetValue("DefaultCLR") as string; if (string.IsNullOrEmpty(version)) return false; return key.OpenSubKey(version) != null; } // Returns an array of all available frameworks of a given type, for example, all mono or all .NET frameworks. public static RuntimeFramework[] GetAvailableFrameworks(RuntimeType rt) { var frameworks = new List<RuntimeFramework>(); if (rt == RuntimeType.Net && Environment.OSVersion.Platform != PlatformID.Unix) { var key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\.NETFramework\policy"); if (key != null) foreach (var name in key.GetSubKeyNames()) if (name.StartsWith("v")) foreach (var build in key.OpenSubKey(name).GetValueNames()) frameworks.Add(new RuntimeFramework(rt, new Version(name.Substring(1) + "." + build))); } else if (rt == RuntimeType.Mono && IsMonoInstalled()) { var framework = new RuntimeFramework(rt, new Version(1, 1, 4322)); framework.DisplayName = "Mono 1.0 Profile"; frameworks.Add(framework); framework = new RuntimeFramework(rt, new Version(2, 0, 50727)); framework.DisplayName = "Mono 2.0 Profile"; frameworks.Add(framework); } return frameworks.ToArray(); } public RuntimeFramework(RuntimeType runtime, Version version) { Runtime = runtime; Version = version; DisplayName = runtime.ToString() + " " + version.ToString(); } public override string ToString() { return DisplayName; } } }
在 RuntimeFramework 类的 CurrentFramework 属性中,如果发现当前环境是 mono 的话,就通过反射调用 Mono.Runtime 类的静态方法 GetDisplayName 来设置 DisplayName 属性。
在 RuntimeFramework 类的静态方法 GetAvailableFrameworks 中,如果发现当前操作系统不是 Unix 的话,就通过遍历注册表的 Software\Microsoft\.NETFramework\policy 项来检测 .NET Framework CLR 版本。
下面是 makefile (关于 makefile,可以参见:GUN make 中文手册):
在 Linux 操作系统下可以用 make 命令编译。在 Windows 操作系统下可以用 nmake 命令编译。
注意,Mono 的 C# 编译器是 gmcs,但是她有个别名叫 csc ,如下所示:
最后,完整的源程序可以到 http://bitbucket.org/ben.skyiv/clrinfo/downloads/ 页面下载。
也可以使用 hg clone http://bitbucket.org/ben.skyiv/clrinfo/ 命令下载。
关于 hg ,请参阅 Mercurial 备忘录。