【问题标题】:Is there an easy way to check the .NET Framework version?有没有简单的方法来检查 .NET Framework 版本?
【发布时间】:2021-12-23 16:41:24
【问题描述】:

问题是我需要知道它是否是版本 3.5 SP 1。Environment.Version() 只返回 2.0.50727.3053

我找到了this solution,但我认为这将花费更多的时间而不是它的价值,所以我正在寻找一个更简单的。有可能吗?

【问题讨论】:

标签: c# .net


【解决方案1】:

这样的事情应该可以做到。只需从注册表中获取值

对于 .NET 1-4

Framework 是最高安装版本,SP 是该版本的服务包。

RegistryKey installed_versions = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP");
string[] version_names = installed_versions.GetSubKeyNames();
//version names start with 'v', eg, 'v3.5' which needs to be trimmed off before conversion
double Framework = Convert.ToDouble(version_names[version_names.Length - 1].Remove(0, 1), CultureInfo.InvariantCulture);
int SP = Convert.ToInt32(installed_versions.OpenSubKey(version_names[version_names.Length - 1]).GetValue("SP", 0));

对于 .NET 4.5+(来自 official documentation):

using System;
using Microsoft.Win32;


...


private static void Get45or451FromRegistry()
{
    using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) {
        int releaseKey = Convert.ToInt32(ndpKey.GetValue("Release"));
        if (true) {
            Console.WriteLine("Version: " + CheckFor45DotVersion(releaseKey));
        }
    }
}


...


// Checking the version using >= will enable forward compatibility,  
// however you should always compile your code on newer versions of 
// the framework to ensure your app works the same. 
private static string CheckFor45DotVersion(int releaseKey)
{
    if (releaseKey >= 528040) {
        return "4.8 or later";
    }
    if (releaseKey >= 461808) {
        return "4.7.2 or later";
    }
    if (releaseKey >= 461308) {
        return "4.7.1 or later";
    }
    if (releaseKey >= 460798) {
        return "4.7 or later";
    }
    if (releaseKey >= 394802) {
        return "4.6.2 or later";
    }
    if (releaseKey >= 394254) {
        return "4.6.1 or later";
    }
    if (releaseKey >= 393295) {
        return "4.6 or later";
    }
    if (releaseKey >= 393273) {
        return "4.6 RC or later";
    }
    if ((releaseKey >= 379893)) {
        return "4.5.2 or later";
    }
    if ((releaseKey >= 378675)) {
        return "4.5.1 or later";
    }
    if ((releaseKey >= 378389)) {
        return "4.5 or later";
    }
    // This line should never execute. A non-null release key should mean 
    // that 4.5 or later is installed. 
    return "No 4.5 or later version detected";
}

【讨论】:

  • 每个 SOFTWARE\Microsoft\NET Framework Setup\NDP\<.net version> 的长版本字符串和 SP 子项应该提供这个,您可以使用 GetValue 方法获取。
  • 这不是在机器上获得最高 INSTALLED 版本的 .NET - 而不是运行应用程序的版本吗?
  • @FactorMystic :您好,我已经使用您的代码检查了最新版本,但即使它安装在我的 PC 中,它也没有列出 4.5 版本。请指导我
  • @FactorMystic 这可以在非管理员 PC 帐户上完成吗?我可以访问注册表值吗?
  • @FactorMystic if (true) 检查的意义何在?为什么不直接打电话给Console.WriteLine()
【解决方案2】:

不知道为什么没有人建议遵循 Microsoft 的官方建议here

这是他们推荐的代码。当然它很丑,但它有效。

对于 .NET 1-4

private static void GetVersionFromRegistry()
{
     // Opens the registry key for the .NET Framework entry. 
        using (RegistryKey ndpKey = 
            RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
            OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
        {
            // As an alternative, if you know the computers you will query are running .NET Framework 4.5  
            // or later, you can use: 
            // using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,  
            // RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
        foreach (string versionKeyName in ndpKey.GetSubKeyNames())
        {
            if (versionKeyName.StartsWith("v"))
            {

                RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                string name = (string)versionKey.GetValue("Version", "");
                string sp = versionKey.GetValue("SP", "").ToString();
                string install = versionKey.GetValue("Install", "").ToString();
                if (install == "") //no install info, must be later.
                    Console.WriteLine(versionKeyName + "  " + name);
                else
                {
                    if (sp != "" && install == "1")
                    {
                        Console.WriteLine(versionKeyName + "  " + name + "  SP" + sp);
                    }

                }
                if (name != "")
                {
                    continue;
                }
                foreach (string subKeyName in versionKey.GetSubKeyNames())
                {
                    RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                    name = (string)subKey.GetValue("Version", "");
                    if (name != "")
                        sp = subKey.GetValue("SP", "").ToString();
                    install = subKey.GetValue("Install", "").ToString();
                    if (install == "") //no install info, must be later.
                        Console.WriteLine(versionKeyName + "  " + name);
                    else
                    {
                        if (sp != "" && install == "1")
                        {
                            Console.WriteLine("  " + subKeyName + "  " + name + "  SP" + sp);
                        }
                        else if (install == "1")
                        {
                            Console.WriteLine("  " + subKeyName + "  " + name);
                        }

                    }

                }

            }
        }
    }

}

适用于 .NET 4.5 及更高版本

// Checking the version using >= will enable forward compatibility, 
// however you should always compile your code on newer versions of
// the framework to ensure your app works the same.
private static string CheckFor45DotVersion(int releaseKey)
{
   if (releaseKey >= 393295) {
      return "4.6 or later";
   }
   if ((releaseKey >= 379893)) {
        return "4.5.2 or later";
    }
    if ((releaseKey >= 378675)) {
        return "4.5.1 or later";
    }
    if ((releaseKey >= 378389)) {
        return "4.5 or later";
    }
    // This line should never execute. A non-null release key should mean
    // that 4.5 or later is installed.
    return "No 4.5 or later version detected";
}

private static void Get45or451FromRegistry()
{
    using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) {
        if (ndpKey != null && ndpKey.GetValue("Release") != null) {
            Console.WriteLine("Version: " + CheckFor45DotVersion((int) ndpKey.GetValue("Release")));
        }
      else {
         Console.WriteLine("Version 4.5 or later is not detected.");
      } 
    }
}

【讨论】:

  • .NET 1-4 的方法有一个错误:它不会打印到 3.0 的原始版本(没有 SP)
  • updates 用于 NET Framework 4.7NET Framework 4.7.1 ?不是 4.7 或更高版本。是的 4.7 或 4.7.1。
  • @Kiquenet 不适合提供的代码吗?
  • 所以要检查 .NET 框架版本,我必须编写代码才能查看它是什么版本?
【解决方案3】:

不需要访问注册表的另一种方法是检查特定框架更新中引入的类是否存在。

private static bool Is46Installed()
{
    // API changes in 4.6: https://github.com/Microsoft/dotnet/blob/master/releases/net46/dotnet46-api-changes.md
    return Type.GetType("System.AppContext, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", false) != null;
}

private static bool Is461Installed()
{
    // API changes in 4.6.1: https://github.com/Microsoft/dotnet/blob/master/releases/net461/dotnet461-api-changes.md
    return Type.GetType("System.Data.SqlClient.SqlColumnEncryptionCngProvider, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", false) != null;
}

private static bool Is462Installed()
{
    // API changes in 4.6.2: https://github.com/Microsoft/dotnet/blob/master/releases/net462/dotnet462-api-changes.md
    return Type.GetType("System.Security.Cryptography.AesCng, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", false) != null;
}

private static bool Is47Installed()
{
    // API changes in 4.7: https://github.com/Microsoft/dotnet/blob/master/releases/net47/dotnet47-api-changes.md
    return Type.GetType("System.Web.Caching.CacheInsertOptions, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false) != null;
}

【讨论】:

  • 4.5 的任何参考?
  • 我喜欢这个主意
  • 和 4.7.1、4.7.2 和 4.8 ?
  • 对我们这些有权限问题的人非常有用
【解决方案4】:

Environment.Version() 给出了不同问题的正确答案。相同版本的 CLR 用于 .NET 2.0、3 和 3.5。我想您可以查看 GAC 以获取在每个后续版本中添加的库。

【讨论】:

  • Environment.Version() 提供2.0,即使它与3.5 一起运行
  • Environment.Version() 为您提供 CLR 的名称。 3.5 不是 CLR 的新版本。它是 2.0 加上一些额外的库,市场驱动的 1.5 增量。
  • 答案具有误导性。 CLR 2.0 用于 .NET 2.0、3.0 和 3.5。 CLR 随版本 4 更改。CLR 4.0 用于 .NET 4.0。
【解决方案5】:

过去很容易,但微软决定做出重大改变:在 4.5 版之前,每个版本的 .NET 都位于C:\Windows\Microsoft.NET\Framework 下的自己的目录中(子目录v1.0.3705, v1.1.4322, v2.0.50727, v3.0, v3.5 和@ 987654328@)。

4.5 版以来,这已更改:每个 .NET 版本(即 4.5.x、4.6.x、4.7.x、4.8.x、...)都安装在相同的子目录 v4.0.30319 - 因此您无法再通过查看 Microsoft.NET\Framework 来检查已安装的 .NET 版本。

为了检查 .NET 版本,Microsoft 已根据要检查的 .NET 版本提供了two different sample scripts,但我不喜欢为此使用两个不同的 C# 脚本。 所以我尝试将它们合二为一,这是我创建的脚本 GetDotNetVersion.cs(并针对 4.7.1 框架进行了更新):

using System;
using Microsoft.Win32;
public class GetDotNetVersion
{
    public static void Main(string[] args)
    {
        Console.WriteLine((args != null && args.Length > 0) 
                          ? "Command line arguments: " + string.Join(",", args) 
                          : "");

        string maxDotNetVersion = GetVersionFromRegistry();
        if (String.Compare(maxDotNetVersion, "4.5") >= 0)
        {
            string v45Plus = GetDotNetVersion.Get45PlusFromRegistry();
            if (v45Plus != "") maxDotNetVersion = v45Plus;
        }
        Console.WriteLine("*** Maximum .NET version number found is: " + maxDotNetVersion + "***");
    }

    private static string Get45PlusFromRegistry()
    {
        String dotNetVersion = "";
        const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
        using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
        {
            if (ndpKey != null && ndpKey.GetValue("Release") != null)
            {
                dotNetVersion = CheckFor45PlusVersion((int)ndpKey.GetValue("Release"));
                Console.WriteLine(".NET Framework Version: " + dotNetVersion);
            }
            else
            {
                Console.WriteLine(".NET Framework Version 4.5 or later is not detected.");
            }
        }
        return dotNetVersion;
    }

    // Checking the version using >= will enable forward compatibility.
    private static string CheckFor45PlusVersion(int releaseKey)
    {
        if (releaseKey >= 528040) return "4.8 or later";
        if (releaseKey >= 461808) return "4.7.2";
        if (releaseKey >= 461308) return "4.7.1";
        if (releaseKey >= 460798) return "4.7";
        if (releaseKey >= 394802) return "4.6.2";
        if (releaseKey >= 394254) return "4.6.1";
        if (releaseKey >= 393295) return "4.6";
        if ((releaseKey >= 379893)) return "4.5.2";
        if ((releaseKey >= 378675)) return "4.5.1";
        if ((releaseKey >= 378389)) return "4.5";

        // This code should never execute. A non-null release key should mean
        // that 4.5 or later is installed.
        return "No 4.5 or later version detected";
    }

    private static string GetVersionFromRegistry()
    {
        String maxDotNetVersion = "";
        // Opens the registry key for the .NET Framework entry.
        using (RegistryKey ndpKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "")
                                        .OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
        {
            // As an alternative, if you know the computers you will query are running .NET Framework 4.5 
            // or later, you can use:
            // using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, 
            // RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
            foreach (string versionKeyName in ndpKey.GetSubKeyNames())
            {
                if (versionKeyName.StartsWith("v"))
                {
                    RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                    string name = (string)versionKey.GetValue("Version", "");
                    string sp = versionKey.GetValue("SP", "").ToString();
                    string install = versionKey.GetValue("Install", "").ToString();
                    if (install == "") //no install info, must be later.
                    {
                        Console.WriteLine(versionKeyName + "  " + name);
                        if (String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                    }
                    else
                    {
                        if (sp != "" && install == "1")
                        {
                            Console.WriteLine(versionKeyName + "  " + name + "  SP" + sp);
                            if (String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                        }

                    }
                    if (name != "")
                    {
                        continue;
                    }
                    foreach (string subKeyName in versionKey.GetSubKeyNames())
                    {
                        RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                        name = (string)subKey.GetValue("Version", "");
                        if (name != "")
                        {
                            sp = subKey.GetValue("SP", "").ToString();
                        }
                        install = subKey.GetValue("Install", "").ToString();
                        if (install == "")
                        {
                            //no install info, must be later.
                            Console.WriteLine(versionKeyName + "  " + name);
                            if (String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                        }
                        else
                        {
                            if (sp != "" && install == "1")
                            {
                                Console.WriteLine("  " + subKeyName + "  " + name + "  SP" + sp);
                                if (String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                            }
                            else if (install == "1")
                            {
                                Console.WriteLine("  " + subKeyName + "  " + name);
                                if (String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                            } // if
                        } // if
                    } // for
                } // if
            } // foreach
        } // using
        return maxDotNetVersion;
    }
    
} // class

在我的机器上输出:

v2.0.50727 2.0.50727.4927 SP2
v3.0 3.0.30729.4926 SP2
v3.5 3.5.30729.4926 SP1
v4
客户端 4.7.03056
完整版 4.7.03056
v4.0
客户端 4.0.0.0
.NET Framework 版本:4.7.2 或更高版本
**** 找到的最大 .NET 版本号为:4.7.2 或更高版本 ****

随着时间的推移,唯一需要维护的是构建号,一旦大于 4.7.1 的 .NET 版本出现 - 这可以通过修改函数 CheckFor45PlusVersion 轻松完成,您需要知道发布密钥对于新版本,您可以添加它。例如:

if (releaseKey >= 461308) return "4.7.1 or later";

发布密钥仍然是最新的,并且适用于 Windows 10 的 Fall Creators 更新。如果您仍在运行其他(旧)Windows 版本,则根据 还有另一个>this 来自 Microsoft 的文档:

.NET Framework 4.7.1 安装在所有其他 Windows 操作系统版本 461310

所以,如果你也需要,你必须添加

if (releaseKey >= 461310) return "4.7.1 or later";

到函数CheckFor45PlusVersion的顶部。 同样,它适用于较新的版本。例如,我最近添加了 4.8 的检查。您通常可以找到这些内部版本号 at Microsoft.


注意:你不需要安装Visual Studio,甚至不需要安装PowerShell——你可以使用csc.exe来编译和运行上面的脚本,我已经描述了@987654324 @


更新:问题是关于 .NET Framework,为了完整起见,我想提一下如何查询 .NET Core 的版本 - 与上面相比,这很容易:打开命令外壳并输入:

dotnet --info 输入

它还会列出 .NET Core 版本号、Windows 版本以及每个相关运行时 DLL 的版本。 示例输出:

.NET Core SDK(反映任何 global.json):
  版本:2.1.300
  提交:adab45bf0c

运行时环境:
  操作系统名称:Windows
  操作系统版本:10.0.15063
  操作系统平台:Windows
  RID:win10-x64
  基本路径:C:\Program Files\dotnet\sdk\2.1.300


主机(用于支持):
  版本:2.1.0
  提交:caa7b7e2ba

.NET Core SDK 已安装:
  1.1.9 [C:\Program Files\dotnet\sdk]
  2.1.102 [C:\Program Files\dotnet\sdk]
  ...
  2.1.300 [C:\Program Files\dotnet\sdk]

.NET Core 运行时已安装:
  Microsoft.AspNetCore.All 2.1.0 [C:\Program
  Files\dotnet\shared\Microsoft.AspNetCore.All]
  ...
  Microsoft.NETCore.App 2.1.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

要安装其他 .NET Core 运行时或 SDK:
  https://aka.ms/dotnet-download

注意

  • 如果您只需要版本号而不需要所有其他信息,您可以使用
    dotnet --version

  • 64位Windows PC上,可以x86版本并排x64一起安装strong> .NET Core 版本。如果是这种情况,您将只能获得环境变量 PATH 中最先出现的版本。 如果您需要保持最新并想了解每个版本,这一点尤其重要。要查询这两个版本,请使用:

C:\Program Files\dotnet\dotnet.exe --version
3.0.100-preview6-012264
C:\Program Files (x86)\dotnet\dotnet.exe --version
3.0.100-preview6-012264

在上面的示例中,两者是相同的,但如果您忘记更新这两个实例,您可能会得到不同的结果!请注意,Program Files64bit 版本,Program Files (x86)32bit 版本。


更新:如果您更喜欢将内部版本号保留在列表中而不是级联的 if 语句中(如 Microsoft 建议的那样),那么您可以将此代码用于 CheckFor45PlusVersion

private static string CheckFor45PlusVersion(int releaseKey)
{
    var release = new SortedDictionary<int, string>()
    {
            { 378389, "4.5" },
            { 378675, "4.5.1" }, { 379893, "4.5.2" },
            { 393295, "4.6" },
            { 394254, "4.6.1" }, { 394802, "4.6.2" },
            { 460798, "4.7" },
            { 461308, "4.7.1" }, { 461808, "4.7.2" },
            { 528040, "4.8 or later" }
    };
    int result = -1;
    foreach(var k in release)
    {
        if (k.Key <= releaseKey) result = k.Key; else break;
    };
    return (result > 0) ? release[result] : "No 4.5 or later version detected";
}

【讨论】:

    【解决方案6】:

    我的 .NET 4.0 类库可能会从 .NET 4.0 或更高版本的程序集调用。

    只有从 4.5+ 程序集执行时,特定的方法调用才会起作用。

    为了决定是否应该调用该方法,我需要确定当前执行的框架版本,这是一个很好的解决方案

    var frameworkName = new System.Runtime.Versioning.FrameworkName(
        AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName
    );
    
    if (frameworkName.Version >= new Version(4, 5)) 
    {
        // run code
    }
    

    更新

    这适用于 4.0 程序集

    var featureEnabled = GetCurrentFrameworkName().Version >= new Version(4, 5);

    public static FrameworkName GetCurrentFrameworkName()
    {
        // AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName
        // is missing prior to .NET 4.5
        var targetFrameworkName = (string)AppDomain
            .CurrentDomain
            .SetupInformation
            .GetType()
            .GetProperty("TargetFrameworkName")?
            .GetValue(AppDomain.CurrentDomain.SetupInformation, null) ?? ".NETFramework,Version=v4.0.0";
    
        return new FrameworkName(targetFrameworkName);
    }
    

    【讨论】:

    • 在浏览了所有这些使用注册表的答案之后,我认为这应该根据原始请求标记为正确答案。他想知道当前正在执行的程序集的 CLR 版本,而不是不一定相同的最大安装版本。此解决方案的唯一警告是它在 .NET 3.5 或更低版本中不起作用,但我很乐意在这些情况下使用 Environment.Version。
    • 我喜欢这种简单性,但请注意 AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName 直到 .Net 4,5 才引入。如果只安装了 .Net 4.0,这段代码会起作用吗?
    • @Giles 你是对的。我已经更新了我的解决方案以考虑到这一点。
    【解决方案7】:

    AFAIK 框架中没有内置方法允许您执行此操作。您可以查看post 以获取有关通过读取 Windows 注册表值来确定框架版本的建议。

    【讨论】:

      【解决方案8】:

      此类允许您的应用程序抛出一个优雅的通知消息,而不是在找不到合适的 .NET 版本时崩溃和烧毁。您需要做的就是在您的主代码中:

      [STAThread]
      static void Main(string[] args)
      {
          if (!DotNetUtils.IsCompatible())
              return;
         . . .
      }
      

      默认情况下它需要 4.5.2,但您可以根据自己的喜好调整它,类(随意将 MessageBox 替换为 Console):

      为 4.8 更新:

      public class DotNetUtils
      {
          public enum DotNetRelease
          {
              NOTFOUND,
              NET45,
              NET451,
              NET452,
              NET46,
              NET461,
              NET462,
              NET47,
              NET471,
              NET472,
              NET48,
          }
      
          public static bool IsCompatible(DotNetRelease req = DotNetRelease.NET452)
          {
              DotNetRelease r = GetRelease();
              if (r < req)
              {
                  MessageBox.Show(String.Format("This this application requires {0} or greater.", req.ToString()));
                  return false;
              }
              return true;
          }
      
          public static DotNetRelease GetRelease(int release = default(int))
          {
              int r = release != default(int) ? release : GetVersion();
              if (r >= 528040) return DotNetRelease.NET48;
              if (r >= 461808) return DotNetRelease.NET472;
              if (r >= 461308) return DotNetRelease.NET471;
              if (r >= 460798) return DotNetRelease.NET47;
              if (r >= 394802) return DotNetRelease.NET462;
              if (r >= 394254) return DotNetRelease.NET461;
              if (r >= 393295) return DotNetRelease.NET46;
              if (r >= 379893) return DotNetRelease.NET452;
              if (r >= 378675) return DotNetRelease.NET451;
              if (r >= 378389) return DotNetRelease.NET45;
              return DotNetRelease.NOTFOUND;
          }
      
          public static int GetVersion()
          {
              int release = 0;
              using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)
                                                  .OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\"))
              {
                  release = Convert.ToInt32(key.GetValue("Release"));
              }
              return release;
          }
      }
      

      以后添加新版本时可以轻松扩展。在 4.5 之前我什么都没有打扰,但你明白了。

      【讨论】:

      【解决方案9】:

      我试图将所有答案组合成一个整体。

      使用:

      NetFrameworkUtilities.GetVersion() 将返回当前可用的 .NET Framework Version,如果不存在,则返回 null

      此示例适用于 .NET Framework 3.5+ 版本。它不需要管理员权限。

      我想指出,您可以使用运算符 来检查版本,如下所示:

      var version = NetFrameworkUtilities.GetVersion();
      if (version != null && version < new Version(4, 5))
      {
          MessageBox.Show("Your .NET Framework version is less than 4.5");
      }
      

      代码:

      using System;
      using System.Linq;
      using Microsoft.Win32;
      
      namespace Utilities
      {
          public static class NetFrameworkUtilities
          {
              public static Version GetVersion() => GetVersionHigher4() ?? GetVersionLowerOr4();
      
              private static Version GetVersionLowerOr4()
              {
                  using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP"))
                  {
                      var names = key?.GetSubKeyNames();
      
                      //version names start with 'v', eg, 'v3.5' which needs to be trimmed off before conversion
                      var text = names?.LastOrDefault()?.Remove(0, 1);
                      if (string.IsNullOrEmpty(text))
                      {
                          return null;
                      }
      
                      return text.Contains('.')
                          ? new Version(text)
                          : new Version(Convert.ToInt32(text), 0);
                  }
              }
      
              private static Version GetVersionHigher4()
              {
                  using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"))
                  {
                      var value = key?.GetValue("Release");
                      if (value == null)
                      {
                          return null;
                      }
      
                      // Checking the version using >= will enable forward compatibility,  
                      // however you should always compile your code on newer versions of 
                      // the framework to ensure your app works the same. 
                      var releaseKey = Convert.ToInt32(value);
                      if (releaseKey >= 528040) return new Version(4, 8, 0);
                      if (releaseKey >= 461808) return new Version(4, 7, 2);
                      if (releaseKey >= 461308) return new Version(4, 7, 1);
                      if (releaseKey >= 460798) return new Version(4, 7);
                      if (releaseKey >= 394747) return new Version(4, 6, 2);
                      if (releaseKey >= 394254) return new Version(4, 6, 1);
                      if (releaseKey >= 381029) return new Version(4, 6);
                      if (releaseKey >= 379893) return new Version(4, 5, 2);
                      if (releaseKey >= 378675) return new Version(4, 5, 1);
                      if (releaseKey >= 378389) return new Version(4, 5);
      
                      // This line should never execute. A non-null release key should mean 
                      // that 4.5 or later is installed. 
                      return new Version(4, 5);
                  }
              }
          }
      }
      

      【讨论】:

      • 好主意,我不知道内置 System.Version 类。
      【解决方案10】:
      public class DA
      {
          public static class VersionNetFramework
          {
              public static string GetVersion()
              {
                  return Environment.Version.ToString();
              }
              public static string GetVersionDicription()
              {
                  int Major = Environment.Version.Major;
                  int Minor = Environment.Version.Minor;
                  int Build = Environment.Version.Build;
                  int Revision = Environment.Version.Revision;
      
                  //http://dzaebel.net/NetVersionen.htm
                  //http://stackoverflow.com/questions/12971881/how-to-reliably-detect-the-actual-net-4-5-version-installed
      
                  //4.0.30319.42000 = .NET 4.6 on Windows 8.1 64 - bit
                  if ((Major >=4) && (Minor >=0) && (Build >= 30319) && (Revision >= 42000))
                      return @".NET 4.6 on Windows 8.1 64 - bit or later";
                  //4.0.30319.34209 = .NET 4.5.2 on Windows 8.1 64 - bit
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 34209))
                      return @".NET 4.5.2 on Windows 8.1 64 - bit or later";
                  //4.0.30319.34209 = .NET 4.5.2 on Windows 7 SP1 64 - bit
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 34209))
                      return @".NET 4.5.2 on Windows 7 SP1 64 - bit or later";
                  //4.0.30319.34014 = .NET 4.5.1 on Windows 8.1 64 - bit
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 34014))
                      return @".NET 4.5.1 on Windows 8.1 64 - bit or later";
                  //4.0.30319.18444 = .NET 4.5.1 on Windows 7 SP1 64 - bit(with MS14 - 009 security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 18444))
                      return @".NET 4.5.1 on Windows 7 SP1 64 - bit(with MS14 - 009 security update) or later";
                  //4.0.30319.18408 = .NET 4.5.1 on Windows 7 SP1 64 - bit
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 18408))
                      return @".NET 4.5.1 on Windows 7 SP1 64 - bit or later";
                  //4.0.30319.18063 = .NET 4.5 on Windows 7 SP1 64 - bit(with MS14 - 009 security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 18063))
                      return @".NET 4.5 on Windows 7 SP1 64 - bit(with MS14 - 009 security update) or later";
                  //4.0.30319.18052 = .NET 4.5 on Windows 7 SP1 64 - bit
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 18052))
                      return @".NET 4.5 on Windows 7 SP1 64 - bit or later";
                  //4.0.30319.18010 = .NET 4.5 on Windows 8
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 18010))
                      return @".NET 4.5 on Windows 8 or later";
                  //4.0.30319.17929 = .NET 4.5 RTM
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 17929))
                      return @".NET 4.5 RTM or later";
                  //4.0.30319.17626 = .NET 4.5 RC
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 17626))
                      return @".NET 4.5 RC or later";
                  //4.0.30319.17020.NET 4.5 Preview, September 2011
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 17020))
                      return @".NET 4.5 Preview, September 2011 or later";
                  //4.0.30319.2034 = .NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS14 - 009 LDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 2034))
                      return @".NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS14 - 009 LDR security update) or later";
                  //4.0.30319.1026 = .NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS14 - 057 GDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 1026))
                      return @".NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS14 - 057 GDR security update) or later";
                  //4.0.30319.1022 = .NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS14 - 009 GDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 1022))
                      return @".NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS14 - 009 GDR security update) or later";
                  //4.0.30319.1008 = .NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS13 - 052 GDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 1008))
                      return @".NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS13 - 052 GDR security update) or later";
                  //4.0.30319.544 = .NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS12 - 035 LDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 544))
                      return @".NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS12 - 035 LDR security update) or later";
                  //4.0.30319.447   yes built by: RTMLDR, .NET 4.0 Platform Update 1, April 2011
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 447))
                      return @"built by: RTMLDR, .NET 4.0 Platform Update 1, April 2011 or later";
                  //4.0.30319.431   yes built by: RTMLDR, .NET 4.0 GDR Update, March 2011 / with VS 2010 SP1 / or.NET 4.0 Update
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 431))
                      return @"built by: RTMLDR, .NET 4.0 GDR Update, March 2011 / with VS 2010 SP1 / or.NET 4.0 Update or later";
                  //4.0.30319.296 = .NET 4.0 on Windows XP SP3, 7(with MS12 - 074 GDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 296))
                      return @".NET 4.0 on Windows XP SP3, 7(with MS12 - 074 GDR security update) or later";
                  //4.0.30319.276 = .NET 4.0 on Windows XP SP3 (4.0.3 Runtime update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 276))
                      return @".NET 4.0 on Windows XP SP3 (4.0.3 Runtime update) or later";
                  //4.0.30319.269 = .NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS12 - 035 GDR security update)
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 269))
                      return @".NET 4.0 on Windows XP SP3, 7, 7 SP1(with MS12 - 035 GDR security update) or later";
                  //4.0.30319.1 yes built by: RTMRel, .NET 4.0 RTM Release, April 2010
                  if ((Major >= 4) && (Minor >= 0) && (Build >= 30319) && (Revision >= 1))
                      return @"built by: RTMRel, .NET 4.0 RTM Release, April 2010 or later";
      
                  //4.0.30128.1     built by: RC1Rel, .NET 4.0 Release Candidate, Feb 2010
                  if ((Major >=4) && (Minor >=0) && (Build >= 30128) && (Revision >= 1))
                      return @"built by: RC1Rel, .NET 4.0 Release Candidate, Feb 2010 or later";
                  //4.0.21006.1     built by: B2Rel, .NET 4.0 Beta2, Oct 2009
                  if ((Major >=4) && (Minor >=0) && (Build >= 21006) && (Revision >=1))
                      return @"built by: B2Rel, .NET 4.0 Beta2, Oct 2009 or later";
                  //4.0.20506.1     built by: Beta1, .NET 4.0 Beta1, May 2009
                  if ((Major >=4) && (Minor >=0) && (Build >= 20506) && (Revision >=1))
                      return @"built by: Beta1, .NET 4.0 Beta1, May 2009 or later";
                  //4.0.11001.1     built by: CTP2 VPC, .NET 4.0 CTP, October 2008
                  if ((Major >=4) && (Minor >=0) && (Build >= 11001) && (Revision >=1))
                      return @"built by: CTP2 VPC, .NET 4.0 CTP, October 2008 or later";
      
                  //3.5.30729.5420  yes built by: Win7SP1, .NET 3.5.1 Sicherheits - Update, 12 April 2011
                  if ((Major >=3) && (Minor >=5) && (Build >= 30729) && (Revision >= 5420))
                      return @"built by: Win7SP1, .NET 3.5.1 Sicherheits - Update, 12 April 2011 or later";
                  //3.5.30729.5004  yes built by: NetFXw7 / Windows 7..Rel., Jan 2010 / +Data functions KB976127 .NET 3.5 SP1
                  if ((Major >=3) && (Minor >=5) && (Build >= 30729) && (Revision >= 5004))
                      return @"built by: NetFXw7 / Windows 7..Rel., Jan 2010 / +Data functions KB976127 .NET 3.5 SP1 or later";
                  //3.5.30729.4466  yes built by: NetFXw7 / Windows XP..Rel. , Jan 2010 / +Data functions KB976127 .NET 3.5 SP1
                  if ((Major >=3) && (Minor >=5) && (Build >= 30729) && (Revision >= 4466))
                      return @"built by: NetFXw7 / Windows XP..Rel. , Jan 2010 / +Data functions KB976127 .NET 3.5 SP1 or later";
                  //3.5.30729.4926  yes built by: NetFXw7 / Windows 7 Release, Oct 2009 / .NET 3.5 SP1 + Hotfixes
                  if ((Major >=3) && (Minor >=5) && (Build >= 30729) && (Revision >= 4926))
                      return @"built by: NetFXw7 / Windows 7 Release, Oct 2009 / .NET 3.5 SP1 + Hotfixes or later";
                  //3.5.30729.4918      built by: NetFXw7 / Windows 7 Release Candidate, June 2009
                  if ((Major >=3) && (Minor >=5) && (Build >= 30729) && (Revision >= 4918))
                      return @"built by: NetFXw7 / Windows 7 Release Candidate, June 2009 or later";
                  //3.5.30729.196   yes built by: QFE, .NET 3.5 Family Update Vista / W2008, Dec 2008
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 30729) && (Revision >=196))
                      return @"built by: QFE, .NET 3.5 Family Update Vista / W2008, Dec 2008 or later";
                  //3.5.30729.1 yes built by: SP, .NET 3.5 SP1, Aug 2008
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 30729) && (Revision >=1))
                      return @"built by: SP, .NET 3.5 SP1, Aug 2008 or later";
      
                  //3.5.30428.1         built by: SP1Beta1, .NET 3.5 SP1 BETA1, May 2008
                  if ((Major >=3) && (Minor >=5) && (Build >= 30428) && (Revision >=1))
                      return @"built by: SP1Beta1, .NET 3.5 SP1 BETA1, May 2008 or later";
                  //3.5.21022.8 yes built by: RTM, Jan 2008
                  if ((Major >=3) && (Minor >=5) && (Build >= 21022) && (Revision >= 8))
                      return @"built by: RTM, Jan 2008 or later";
                  //3.5.20706.1     built by: Beta2, Orcas Beta2, Oct 2007
                  if ((Major >=3) && (Minor >=5) && (Build >= 20706) && (Revision >= 1))
                      return @"built by: Beta2, Orcas Beta2, Oct 2007 or later";
                  //3.5.20526.0     built by: MCritCTP, Orcas Beta1, Mar 2007
                  if ((Major >=3) && (Minor >=5) && (Build >= 20526) && (Revision >=0))
                      return @"built by: MCritCTP, Orcas Beta1, Mar 2007 or later";
      
                  //3.0.6920.1500   yes built by: QFE, Family Update Vista / W2008, Dez 2008, KB958483
                  if ((Major >=3) && (Minor >=0) && (Build >= 6920) && (Revision >= 1500))
                      return @"built by: QFE, Family Update Vista / W2008, Dez 2008, KB958483 or later";
                  //3.0.4506.4926   yes(NetFXw7.030729 - 4900) / Windows 7 Release, Oct 2009
                  if ((Major >=3) && (Minor >=0) && (Build >= 4506) && (Revision >= 4926))
                      return @"(NetFXw7.030729 - 4900) / Windows 7 Release, Oct 2009 or later";
                  //3.0.4506.4918(NetFXw7.030729 - 4900) / Windows 7 Release Candidate, June 2009
                  if ((Major >=3) && (Minor >=5) && (Build >= 4506) && (Revision >= 4918))
                      return @"(NetFXw7.030729 - 4900) / Windows 7 Release Candidate, June 2009 or later";
                  //3.0.4506.2152       3.0.4506.2152(SP.030729 - 0100) / .NET 4.0 Beta1 / May 2009
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 2152))
                      return @"3.0.4506.2152(SP.030729 - 0100) / .NET 4.0 Beta1 / May 2009 or later";
                  //3.0.4506.2123   yes(NetFX.030618 - 0000).NET 3.0 SP2, Aug 2008
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 2123))
                      return @"s(NetFX.030618 - 0000).NET 3.0 SP2, Aug 2008 or later";
                  //3.0.4506.2062(SP1Beta1.030428 - 0100), .NET 3.0 SP1 BETA1, May 2008
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 2062))
                      return @"(SP1Beta1.030428 - 0100), .NET 3.0 SP1 BETA1, May 2008 or later";
                  //3.0.4506.590(winfxredb2.004506 - 0590), Orcas Beta2, Oct 2007
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 590))
                      return @"(winfxredb2.004506 - 0590), Orcas Beta2, Oct 2007 or later";
                  //3.0.4506.577(winfxred.004506 - 0577), Orcas Beta1, Mar 2007
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 577))
                      return @"(winfxred.004506 - 0577), Orcas Beta1, Mar 2007 or later";
                  //3.0.4506.30 yes Release (.NET Framework 3.0) Nov 2006
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 30))
                      return @"Release (.NET Framework 3.0) Nov 2006 or later";
                  //3.0.4506.25 yes(WAPRTM.004506 - 0026) Vista Ultimate, Jan 2007
                  if ((Major >= 3) && (Minor >= 5) && (Build >= 4506) && (Revision >= 25))
                      return @"(WAPRTM.004506 - 0026) Vista Ultimate, Jan 2007 or later";
      
                  //2.0.50727.4927  yes(NetFXspW7.050727 - 4900) / Windows 7 Release, Oct 2009
                  if ((Major >=2) && (Minor >=0) && (Build >= 50727) && (Revision >= 4927))
                      return @"(NetFXspW7.050727 - 4900) / Windows 7 Release, Oct 2009 or later";
                  //2.0.50727.4918(NetFXspW7.050727 - 4900) / Windows 7 Release Candidate, June 2009
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 4918))
                      return @"(NetFXspW7.050727 - 4900) / Windows 7 Release Candidate, June 2009 or later";
                  //2.0.50727.4200  yes(NetFxQFE.050727 - 4200).NET 2.0 SP2, KB974470, Securityupdate, Oct 2009
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 4200))
                      return @"(NetFxQFE.050727 - 4200).NET 2.0 SP2, KB974470, Securityupdate, Oct 2009 or later";
                  //2.0.50727.3603(GDR.050727 - 3600).NET 4.0 Beta 2, Oct 2009
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 3603))
                      return @"(GDR.050727 - 3600).NET 4.0 Beta 2, Oct 2009 or later";
                  //2.0.50727.3082  yes(QFE.050727 - 3000), .NET 3.5 Family Update XP / W2003, Dez 2008, KB958481
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 3082))
                      return @"(QFE.050727 - 3000), .NET 3.5 Family Update XP / W2003, Dez 2008, KB958481 or later";
                  //2.0.50727.3074  yes(QFE.050727 - 3000), .NET 3.5 Family Update Vista / W2008, Dez 2008, KB958481
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 3074))
                      return @"(QFE.050727 - 3000), .NET 3.5 Family Update Vista / W2008, Dez 2008, KB958481 or later";
                  //2.0.50727.3053  yes(netfxsp.050727 - 3000), .NET 2.0 SP2, Aug 2008
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 3053))
                      return @"yes(netfxsp.050727 - 3000), .NET 2.0 SP2, Aug 2008 or later";
                  //2.0.50727.3031(netfxsp.050727 - 3000), .NET 2.0 SP2 Beta 1, May 2008
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 3031))
                      return @"(netfxsp.050727 - 3000), .NET 2.0 SP2 Beta 1, May 2008 or later";
                  //2.0.50727.1434  yes(REDBITS.050727 - 1400), Windows Server 2008 and Windows Vista SP1, Dez 2007
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 1434))
                      return @"(REDBITS.050727 - 1400), Windows Server 2008 and Windows Vista SP1, Dez 2007 or later";
                  //2.0.50727.1433  yes(REDBITS.050727 - 1400), .NET 2.0 SP1 Release, Nov 2007, http://www.microsoft.com/downloads/details.aspx?FamilyID=79bc3b77-e02c-4ad3-aacf-a7633f706ba5
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 1433))
                      return @"(REDBITS.050727 - 1400), .NET 2.0 SP1 Release, Nov 2007 or later";
                  //2.0.50727.1378(REDBITSB2.050727 - 1300), Orcas Beta2, Oct 2007
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 1378))
                      return @"(REDBITSB2.050727 - 1300), Orcas Beta2, Oct 2007 or later";
                  //2.0.50727.1366(REDBITS.050727 - 1300), Orcas Beta1, Mar 2007
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 1366))
                      return @"(REDBITS.050727 - 1300), Orcas Beta1, Mar 2007 or later";
                  //2.0.50727.867   yes(VS Express Edition 2005 SP1), Apr 2007, http://www.microsoft.com/downloads/details.aspx?FamilyId=7B0B0339-613A-46E6-AB4D-080D4D4A8C4E
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 867))
                      return @"(VS Express Edition 2005 SP1), Apr 2007 or later";
                  //2.0.50727.832(Fix x86 VC++2005), Apr 2007, http://support.microsoft.com/kb/934586/en-us
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 832))
                      return @"(Fix x86 VC++2005), Apr 2007 or later";
                  //2.0.50727.762   yes(VS TeamSuite SP1), http://www.microsoft.com/downloads/details.aspx?FamilyId=BB4A75AB-E2D4-4C96-B39D-37BAF6B5B1DC
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 762))
                      return @"(VS TeamSuite SP1) or later";
                  //2.0.50727.312   yes(rtmLHS.050727 - 3100) Vista Ultimate, Jan 2007
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 312))
                      return @"(rtmLHS.050727 - 3100) Vista Ultimate, Jan 2007 or later";
                  //2.0.50727.42    yes Release (.NET Framework 2.0) Oct 2005
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 42))
                      return @"Release (.NET Framework 2.0) Oct 2005 or later";
                  //2.0.50727.26        Version 2.0(Visual Studio Team System 2005 Release Candidate) Oct 2005
                  if ((Major >= 2) && (Minor >= 0) && (Build >= 50727) && (Revision >= 26))
                      return @"Version 2.0(Visual Studio Team System 2005 Release Candidate) Oct 2005 or later";
      
                  //2.0.50712       Version 2.0(Visual Studio Team System 2005(Drop3) CTP) July 2005
                  if ((Major >=2) && (Minor >=0) && (Build >= 50712))
                      return @"Version 2.0(Visual Studio Team System 2005(Drop3) CTP) July 2005 or later";
                  //2.0.50215       Version 2.0(WinFX SDK for Indigo / Avalon 2005 CTP) July 2005
                  if ((Major >=2) && (Minor >=0) && (Build >= 50215))
                      return @"Version 2.0(WinFX SDK for Indigo / Avalon 2005 CTP) July 2005 or later";
                  //2.0.50601.0     Version 2.0(Visual Studio.NET 2005 CTP) June 2005
                  if ((Major >=2) && (Minor >=0) && (Build >= 50601) && (Revision >=0))
                      return @"Version 2.0(Visual Studio.NET 2005 CTP) June 2005 or later";
                  //2.0.50215.44        Version 2.0(Visual Studio.NET 2005 Beta 2, Visual Studio Express Beta 2) Apr 2005
                  if ((Major >=2) && (Minor >=0) && (Build >= 50215) && (Revision >= 44))
                      return @"Version 2.0(Visual Studio.NET 2005 Beta 2, Visual Studio Express Beta 2) Apr 2005 or later";
                  //2.0.50110.28        Version 2.0(Visual Studio.NET 2005 CTP, Professional Edition) Feb 2005
                  if ((Major >=2) && (Minor >=0) && (Build >= 50110) && (Revision >=28))
                      return @"Version 2.0(Visual Studio.NET 2005 CTP, Professional Edition) Feb 2005 or later";
                  //2.0.41115.19        Version 2.0(Visual Studio.NET 2005 Beta 1, Team System Refresh) Dec 2004
                  if ((Major >=2 ) && (Minor >=0 ) && (Build >= 41115) && (Revision >= 19))
                      return @"Version 2.0(Visual Studio.NET 2005 Beta 1, Team System Refresh) Dec 2004 or later";
                  //2.0.40903.0         Version 2.0(Whidbey CTP, Visual Studio Express) Oct 2004
                  if ((Major >=2) && (Minor >=0) && (Build >= 40903) && (Revision >=0))
                      return @"Version 2.0(Whidbey CTP, Visual Studio Express) Oct 2004 or later";
                  //2.0.40607.85        Version 2.0(Visual Studio.NET 2005 Beta 1, Team System Refresh) Aug 2004 *
                  if ((Major >=2) && (Minor >=0) && (Build >= 40607) && (Revision >= 85))
                      return @"Version 2.0(Visual Studio.NET 2005 Beta 1, Team System Refresh) Aug 2004 * or later";
                  //2.0.40607.42        Version 2.0(SQL Server Yukon Beta 2) July 2004
                  if ((Major >=2) && (Minor >=0) && (Build >= 40607) && (Revision >= 42))
                      return @"Version 2.0(SQL Server Yukon Beta 2) July 2004 or later";
                  //2.0.40607.16        Version 2.0(Visual Studio.NET 2005 Beta 1, TechEd Europe 2004) June 2004
                  if ((Major >=2) && (Minor >=0) && (Build >= 40607) && (Revision >= 16))
                      return @"Version 2.0(Visual Studio.NET 2005 Beta 1, TechEd Europe 2004) June 2004 or later";
                  //2.0.40301.9         Version 2.0(Whidbey CTP, WinHEC 2004) March 2004 *
                  if ((Major >=0) && (Minor >=0) && (Build >= 40301) && (Revision >=9))
                      return @"Version 2.0(Whidbey CTP, WinHEC 2004) March 2004 * or later";
      
                  //1.2.30703.27        Version 1.2(Whidbey Alpha, PDC 2004) Nov 2003 *
                  if ((Major >=1) && (Minor >=2) && (Build >= 30703) && (Revision >= 27))
                      return @"Version 1.2(Whidbey Alpha, PDC 2004) Nov 2003 * or later";
                  //1.2.21213.1     Version 1.2(Whidbey pre - Alpha build) *
                  if ((Major >=1) && (Minor >=2) && (Build >= 21213) && (Revision >=1))
                      return @"Version 1.2(Whidbey pre - Alpha build) * or later";
      
                  //1.1.4322.2443   yes Version 1.1 Servicepack 1, KB953297, Oct 2009
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >=2443))
                      return @"Version 1.1 Servicepack 1, KB953297, Oct 2009 or later";
                  //1.1.4322.2407   yes Version 1.1 RTM
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >= 2407))
                      return @"Version 1.1 RTM or later";
                  //1.1.4322.2407       Version 1.1 Orcas Beta2, Oct 2007
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >= 2407))
                      return @"Version 1.1 Orcas Beta2, Oct 2007 or later";
                  //1.1.4322.2379       Version 1.1 Orcas Beta1, Mar 2007
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >= 2379))
                      return @"Version 1.1 Orcas Beta1, Mar 2007 or later";
                  //1.1.4322.2032   yes Version 1.1 SP1 Aug 2004
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >= 2032))
                      return @"Version 1.1 SP1 Aug 2004 or later";
                  //1.1.4322.573    yes Version 1.1 RTM(Visual Studio.NET 2003 / Windows Server 2003) Feb 2003 *
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >= 573))
                      return @"Version 1.1 RTM(Visual Studio.NET 2003 / Windows Server 2003) Feb 2003 * or later";
                  //1.1.4322.510        Version 1.1 Final Beta Oct 2002 *
                  if ((Major >=1) && (Minor >=1) && (Build >= 4322) && (Revision >= 510))
                      return @"Version 1.1 Final Beta Oct 2002 * or later";
      
                  //1.0.3705.6018   yes Version 1.0 SP3 Aug 2004
                  if ((Major >=1) && (Minor >=0) && (Build >= 3705) && (Revision >= 6018))
                      return @"Version 1.0 SP3 Aug 2004 or later";
                  //1.0.3705.288    yes Version 1.0 SP2 Aug 2002 *
                  if ((Major >=1) && (Minor >=0) && (Build >= 3705) && (Revision >= 288))
                      return @"Version 1.0 SP2 Aug 2002 * or later";
                  //1.0.3705.209    yes Version 1.0 SP1 Mar 2002 *
                  if ((Major >=1) && (Minor >=0) && (Build >= 3705) && (Revision >=209))
                      return @"Version 1.0 SP1 Mar 2002 * or later";
                  //1.0.3705.0  yes Version 1.0 RTM(Visual Studio.NET 2002) Feb 2002 *
                  if ((Major >=1) && (Minor >=0) && (Build >= 3705) && (Revision >=0))
                      return @"Version 1.0 RTM(Visual Studio.NET 2002) Feb 2002 * or later";
                  //1.0.3512.0      Version 1.0 Pre - release RC3(Visual Studio.NET 2002 RC3)
                  if ((Major >=1) && (Minor >=0) && (Build >= 3512) && (Revision >=0))
                      return @"Version 1.0 Pre - release RC3(Visual Studio.NET 2002 RC3) or later";
                  //1.0.2914.16     Version 1.0 Public Beta 2 Jun 2001 *
                  if ((Major >=1) && (Minor >=0) && (Build >= 2914) && (Revision >= 16))
                      return @"Version 1.0 Public Beta 2 Jun 2001 * or later";
                  //1.0.2204.21         Version 1.0 Public Beta 1 Nov 2000 *
                  if ((Major >=1) && (Minor >=0) && (Build >= 2204) && (Revision >=21))
                      return @"Version 1.0 Public Beta 1 Nov 2000 * or later";
      
                  return @"Unknown .NET version";
              }
          }
      }
      

      【讨论】:

      • 正文限制30000个字符所有代码是34045个字符这个最重的代码部分
      • 这很好,但你能把它删减成一个适合作为单一答案的东西吗?
      • 但是这个代码部分只提供了一种方法 DA.VersionNetFramework.GetVersionDicription()
      • 仅供参考,我将其构建为 2.0 应用程序,将其放入控制台并在具有 4.6 的系统上返回“'2.0.50727.5485'”,因此看起来 Environment.Version 可能不会返回已安装的内容与运行应用程序所使用的一样多看起来唯一安全的方法是检查注册表。
      • 对于 NET Framework 4.7NET Framework 4.7.1 呢?跨度>
      【解决方案11】:

      感谢您的这篇非常有用的帖子。 我不得不稍微调整一下以检查框架 2.0,因为注册表项不能直接转换为双精度。代码如下:

      string[] version_names = rk.GetSubKeyNames();
      //version names start with 'v', eg, 'v3.5'
      //we also need to take care of strings like v2.0.50727...
      string sCurrent = version_names[version_names.Length - 1].Remove(0, 1);
      if (sCurrent.LastIndexOf(".") > 1)
      {
          string[] sSplit = sCurrent.Split('.');
          sCurrent = sSplit[0] + "." + sSplit[1] + sSplit[2];
      }
      double dCurrent = Convert.ToDouble(sCurrent, System.Globalization.CultureInfo.InvariantCulture);
      double dExpected = Convert.ToDouble(sExpectedVersion);
      if (dCurrent >= dExpected)
      

      【讨论】:

      • 您真的不应该将版本号存储为双精度数。他们很容易四舍五入。使用小数。
      【解决方案12】:
      public class DA {
        public static class VersionNetFramework {
          public static string Get45or451FromRegistry()
          {//https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
              using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\"))
              {
                  int releaseKey = Convert.ToInt32(ndpKey.GetValue("Release"));
                  if (true)
                  {
                      return (@"Version: " + CheckFor45DotVersion(releaseKey));
                  }
              }
          }
          // Checking the version using >= will enable forward compatibility, 
          // however you should always compile your code on newer versions of
          // the framework to ensure your app works the same.
          private static string CheckFor45DotVersion(int releaseKey)
          {//https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
              if (releaseKey >= 394271)
                  return "4.6.1 installed on all other Windows OS versions or later";
              if (releaseKey >= 394254)
                  return "4.6.1 installed on Windows 10 or later";
              if (releaseKey >= 393297)
                  return "4.6 installed on all other Windows OS versions or later";
              if (releaseKey >= 393295)
                  return "4.6 installed with Windows 10 or later";
              if (releaseKey >= 379893)
                  return "4.5.2 or later";
              if (releaseKey >= 378758)
                  return "4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2 or later";
              if (releaseKey >= 378675)
                  return "4.5.1 installed with Windows 8.1 or later";
              if (releaseKey >= 378389)
                  return "4.5 or later";
      
              return "No 4.5 or later version detected";
          }
          public static string GetVersionFromRegistry()
          {//https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
              string res = @"";
              // Opens the registry key for the .NET Framework entry.
              using (RegistryKey ndpKey =
                  RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
                  OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
              {
                  // As an alternative, if you know the computers you will query are running .NET Framework 4.5 
                  // or later, you can use:
                  // using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, 
                  // RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
                  foreach (string versionKeyName in ndpKey.GetSubKeyNames())
                  {
                      if (versionKeyName.StartsWith("v"))
                      {
      
                          RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                          string name = (string)versionKey.GetValue("Version", "");
                          string sp = versionKey.GetValue("SP", "").ToString();
                          string install = versionKey.GetValue("Install", "").ToString();
                          if (install == "") //no install info, must be later.
                              res += (versionKeyName + "  " + name) + Environment.NewLine;
                          else
                          {
                              if (sp != "" && install == "1")
                              {
                                  res += (versionKeyName + "  " + name + "  SP" + sp) + Environment.NewLine;
                              }
      
                          }
                          if (name != "")
                          {
                              continue;
                          }
                          foreach (string subKeyName in versionKey.GetSubKeyNames())
                          {
                              RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                              name = (string)subKey.GetValue("Version", "");
                              if (name != "")
                                  sp = subKey.GetValue("SP", "").ToString();
                              install = subKey.GetValue("Install", "").ToString();
                              if (install == "") //no install info, must be later.
                                  res += (versionKeyName + "  " + name) + Environment.NewLine;
                              else
                              {
                                  if (sp != "" && install == "1")
                                  {
                                      res += ("  " + subKeyName + "  " + name + "  SP" + sp) + Environment.NewLine;
                                  }
                                  else if (install == "1")
                                  {
                                      res += ("  " + subKeyName + "  " + name) + Environment.NewLine;
                                  }
                              }
                          }
                      }
                  }
              }
              return res;
          }
          public static string GetUpdateHistory()
          {//https://msdn.microsoft.com/en-us/library/hh925567(v=vs.110).aspx
              string res=@"";
              using (RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\Updates"))
              {
                  foreach (string baseKeyName in baseKey.GetSubKeyNames())
                  {
                      if (baseKeyName.Contains(".NET Framework") || baseKeyName.StartsWith("KB") || baseKeyName.Contains(".NETFramework"))
                      {
      
                          using (RegistryKey updateKey = baseKey.OpenSubKey(baseKeyName))
                          {
                              string name = (string)updateKey.GetValue("PackageName", "");
                              res += baseKeyName + "  " + name + Environment.NewLine;
                              foreach (string kbKeyName in updateKey.GetSubKeyNames())
                              {
                                  using (RegistryKey kbKey = updateKey.OpenSubKey(kbKeyName))
                                  {
                                      name = (string)kbKey.GetValue("PackageName", "");
                                      res += ("  " + kbKeyName + "  " + name) + Environment.NewLine;
      
                                      if (kbKey.SubKeyCount > 0)
                                      {
                                          foreach (string sbKeyName in kbKey.GetSubKeyNames())
                                          {
                                              using (RegistryKey sbSubKey = kbKey.OpenSubKey(sbKeyName))
                                              {
                                                  name = (string)sbSubKey.GetValue("PackageName", "");
                                                  if (name == "")
                                                      name = (string)sbSubKey.GetValue("Description", "");
                                                  res += ("    " + sbKeyName + "  " + name) + Environment.NewLine;
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
              return res;
          }
      }
      

      使用 DA.VersionNetFramework 类

      private void Form1_Shown(object sender, EventArgs e)
      {
          //
          // Current OS Information
          //
          richTextBox1.Text = @"Current OS Information:";
          richTextBox1.AppendText(Environment.NewLine +
                                  "Machine Name: " + Environment.MachineName);
          richTextBox1.AppendText(Environment.NewLine +
                                  "Platform: " + Environment.OSVersion.Platform.ToString());
          richTextBox1.AppendText(Environment.NewLine +
                                  Environment.OSVersion);
          //
          // .NET Framework Environment Information
          //
          richTextBox1.AppendText(Environment.NewLine + Environment.NewLine +
                                             ".NET Framework Environment Information:");
          richTextBox1.AppendText(Environment.NewLine +
                                  "Environment.Version " + Environment.Version);
          richTextBox1.AppendText(Environment.NewLine + 
                                  DA.VersionNetFramework.GetVersionDicription());
          //
          // .NET Framework Information From Registry
          //
          richTextBox1.AppendText(Environment.NewLine + Environment.NewLine +
                                             ".NET Framework Information From Registry:");
          richTextBox1.AppendText(Environment.NewLine +
                                  DA.VersionNetFramework.GetVersionFromRegistry());
          //
          // .NET Framework 4.5 or later Information From Registry
          //
          richTextBox1.AppendText(Environment.NewLine + 
                                             ".NET Framework 4.5 or later Information From Registry:");
          richTextBox1.AppendText(Environment.NewLine +
                                  DA.VersionNetFramework.Get45or451FromRegistry());
          //
          // Update History
          //
          richTextBox1.AppendText(Environment.NewLine + Environment.NewLine +
                                  "Update History");
          richTextBox1.AppendText(Environment.NewLine + 
                                  DA.VersionNetFramework.GetUpdateHistory());
          //
          // Setting Cursor to first character of textbox
          //
          if (!richTextBox1.Text.Equals(""))
          {
              richTextBox1.SelectionStart = 1;
          }
      }
      

      结果:

      当前操作系统信息: 机器名称:D1 平台:Win32NT 微软视窗 NT 6.2.9200.0

      .NET Framework 环境信息: 环境.版本 4.0.30319.42000 Windows 8.1 64 位或更高版本上的 .NET 4.6

      来自注册表的 .NET Framework 信息: v2.0.50727 2.0.50727.4927 SP2 v3.0 3.0.30729.4926 SP2 v3.5 3.5.30729.4926 SP1

      v4
      客户端 4.6.00079 完整的 4.6.00079 v4.0
      客户端 4.0.0.0

      .NET Framework 4.5 或更高版本 来自注册表的信息: 版本:4.6 随 Windows 10 或更高版本安装

      更新历史 Microsoft .NET Framework 4 客户端配置文件
      KB2468871
      KB2468871v2
      KB2478063
      KB2533523
      KB2544514
      KB2600211
      KB2600217
      Microsoft .NET Framework 4 扩展版
      KB2468871
      KB2468871v2
      KB2478063
      KB2533523
      KB2544514
      KB2600211
      KB2600217
      Microsoft .NET Framework 4 多目标包
      (KB2504637) 的 KB2504637 更新

      【讨论】:

      • 正文限制30000个字符所有代码是34045个字符这个最轻的代码部分
      • 对于 NET Framework 4.7NET Framework 4.7.1 呢?跨度>
      【解决方案13】:

      我已经更改了 Matt 的类,因此它可以在任何项目中重复使用,而无需在控制台上打印所有检查并返回一个安装了正确最大版本的简单字符串。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using Microsoft.Win32;
      
      namespace MyNamespace
      {
          public class DotNetVersion
          {
              protected bool printVerification;
      
              public DotNetVersion(){
                  this.printVerification=false;
              }
              public DotNetVersion(bool printVerification){
                  this.printVerification=printVerification;
              }
      
      
              public string getDotNetVersion(){
                  string maxDotNetVersion = getVersionFromRegistry();
                  if(String.Compare(maxDotNetVersion, "4.5") >= 0){
                      string v45Plus = get45PlusFromRegistry();
                      if(!string.IsNullOrWhiteSpace(v45Plus)) maxDotNetVersion = v45Plus;
                  }
                  log("*** Maximum .NET version number found is: " + maxDotNetVersion + "***");
      
                  return maxDotNetVersion;
              }
      
              protected string get45PlusFromRegistry(){
                  String dotNetVersion = "";
                  const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
                  using(RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)){
                      if(ndpKey != null && ndpKey.GetValue("Release") != null){
                          dotNetVersion = checkFor45PlusVersion((int)ndpKey.GetValue("Release"));
                          log(".NET Framework Version: " + dotNetVersion);
                      }else{
                          log(".NET Framework Version 4.5 or later is not detected.");
                      }
                  }
                  return dotNetVersion;
              }
      
              // Checking the version using >= will enable forward compatibility.
              protected string checkFor45PlusVersion(int releaseKey){
                  if(releaseKey >= 461308) return "4.7.1 or later";
                  if(releaseKey >= 460798) return "4.7";
                  if(releaseKey >= 394802) return "4.6.2";
                  if(releaseKey >= 394254) return "4.6.1";
                  if(releaseKey >= 393295) return "4.6";
                  if((releaseKey >= 379893)) return "4.5.2";
                  if((releaseKey >= 378675)) return "4.5.1";
                  if((releaseKey >= 378389)) return "4.5";
      
                  // This code should never execute. A non-null release key should mean
                  // that 4.5 or later is installed.
                  log("No 4.5 or later version detected");
                  return "";
              }
      
              protected string getVersionFromRegistry(){
                  String maxDotNetVersion = "";
                  // Opens the registry key for the .NET Framework entry.
                  using(RegistryKey ndpKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "")
                                                  .OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\")){
                      // As an alternative, if you know the computers you will query are running .NET Framework 4.5 
                      // or later, you can use:
                      // using(RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, 
                      // RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
                      string[] subKeyNnames = ndpKey.GetSubKeyNames();
                      foreach(string versionKeyName in subKeyNnames){
                          if(versionKeyName.StartsWith("v")){
                              RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                              string name =(string)versionKey.GetValue("Version", "");
                              string sp = versionKey.GetValue("SP", "").ToString();
                              string install = versionKey.GetValue("Install", "").ToString();
                              if(string.IsNullOrWhiteSpace(install)){ //no install info, must be later.
                                  log(versionKeyName + "  " + name);
                                  if(String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                              }else{
                                  if(!string.IsNullOrWhiteSpace(sp) && "1".Equals(install)){
                                      log(versionKeyName + "  " + name + "  SP" + sp);
                                      if(String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                                  }
      
                              }
                              if(!string.IsNullOrWhiteSpace(name)){
                                  continue;
                              }
      
                              string[] subKeyNames = versionKey.GetSubKeyNames();
                              foreach(string subKeyName in subKeyNames){
                                  RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                                  name =(string)subKey.GetValue("Version", "");
                                  if(!string.IsNullOrWhiteSpace(name)){
                                      sp = subKey.GetValue("SP", "").ToString();
                                  }
                                  install = subKey.GetValue("Install", "").ToString();
                                  if(string.IsNullOrWhiteSpace(install)){
                                      //no install info, must be later.
                                      log(versionKeyName + "  " + name);
                                      if(String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                                  }else{
                                      if(!string.IsNullOrWhiteSpace(sp) && "1".Equals(install)){
                                          log("  " + subKeyName + "  " + name + "  SP" + sp);
                                          if(String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                                      }
                                      else if("1".Equals(install)){
                                          log("  " + subKeyName + "  " + name);
                                          if(String.Compare(maxDotNetVersion, name) < 0) maxDotNetVersion = name;
                                      } // if
                                  } // if
                              } // for
                          } // if
                      } // foreach
                  } // using
                  return maxDotNetVersion;
              }
      
              protected void log(string message){
                  if(printVerification) Console.WriteLine(message);
              }
      
          } // class
      }
      

      【讨论】:

        【解决方案14】:

        使用 .NET 4.6.2 更新。检查与先前响应相同的注册表中的 Release 值:

        RegistryKey registry_key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full");
        if (registry_key == null)
            return false;
        var val = registry_key.GetValue("Release", 0);
        UInt32 Release = Convert.ToUInt32(val);
        
        if (Release >= 394806) // 4.6.2 installed on all other Windows (different than Windows 10)
                        return true;
        if (Release >= 394802) // 4.6.2 installed on Windows 10 or later
                        return true;
        

        【讨论】:

        • updates 用于 NET Framework 4.7NET Framework 4.7.1 ?
        【解决方案15】:

        您可以得到一个有用的字符串,而无需触摸注册表或引用可能会或可能不会加载的程序集。 mscorlib.dll 和其他系统程序集定义了 AssemblyFileVersionAttribute,并且基于 Visual Studio 提供的参考程序集,它似乎对于每个版本的 .NET 都是唯一的。

        string version = (typeof(string).Assembly
            .GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false)
            .FirstOrDefault() as AssemblyFileVersionAttribute)?.Version;
        

        4.5 版本有点偏离,因为它在该版本中标记为 4.0,但 4.6 及更高版本似乎至少与次要版本匹配。这样做似乎比依赖某些安装程序注册表项并必须与一组固定值进行比较更能证明未来。

        我在这里找到了参考程序集:

        C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework
        

        我从哪里得到以下版本:

        4.0 = 4.0.30319.1
        4.5 = 4.0.30319.18020
        4.5.1 = 4.0.30319.18402
        4.5.2 = 4.0.30319.34211
        4.6 = 4.6.81.0
        4.6.1 = 4.6.1055.0
        4.7.2 = 4.7.3062.0
        4.8 = 4.8.3761.0
        

        【讨论】:

          【解决方案16】:

          有点大,但看起来它是最新的微软怪事:

              public static class Versions
              {
                  static Version 
                      _NET;
          
                  static SortedList<String,Version>
                      _NETInstalled;
          
          #if NET40
          #else
                  public static bool VersionTry(String S, out Version V)
                  {
                      try
                      { 
                          V=new Version(S); 
                          return true;
                      }
                      catch
                      {
                          V=null;
                          return false;
                      }
                  }
          #endif
                  const string _NetFrameWorkKey = "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP";
                  static void FillNetInstalled()
                  {
                      if (_NETInstalled == null)
                      {
                          _NETInstalled = new SortedList<String, Version>(StringComparer.InvariantCultureIgnoreCase);
                          RegistryKey
                              frmks = Registry.LocalMachine.OpenSubKey(_NetFrameWorkKey);
                          string[]
                              names = frmks.GetSubKeyNames();
                          foreach (string name in names)
                          {
                              if (name.StartsWith("v", StringComparison.InvariantCultureIgnoreCase) && name.Length > 1)
                              {
                                  string
                                      f, vs;
                                  Version
                                      v;
                                  vs = name.Substring(1);
                                  if (vs.IndexOf('.') < 0)
                                      vs += ".0";
          #if NET40
                                  if (Version.TryParse(vs, out v))
          #else
                                  if (VersionTry(vs, out v))
          #endif
                                  {
                                      f = String.Format("{0}.{1}", v.Major, v.Minor);
          #if NET40
                                      if (Version.TryParse((string)frmks.OpenSubKey(name).GetValue("Version"), out v))
          #else
                                      if (VersionTry((string)frmks.OpenSubKey(name).GetValue("Version"), out v))
          #endif
                                      {
                                          if (!_NETInstalled.ContainsKey(f) || v.CompareTo(_NETInstalled[f]) > 0)
                                              _NETInstalled[f] = v;
                                      }
                                      else
                                      { // parse variants
                                          Version
                                              best = null;
                                          if (_NETInstalled.ContainsKey(f))
                                              best = _NETInstalled[f];
                                          string[]
                                              varieties = frmks.OpenSubKey(name).GetSubKeyNames();
                                          foreach (string variety in varieties)
          #if NET40
                                              if (Version.TryParse((string)frmks.OpenSubKey(name + '\\' + variety).GetValue("Version"), out v))
          #else
                                              if (VersionTry((string)frmks.OpenSubKey(name + '\\' + variety).GetValue("Version"), out v))
          #endif
                                              {
                                                  if (best == null || v.CompareTo(best) > 0)
                                                  {
                                                      _NETInstalled[f] = v;
                                                      best = v;
                                                  }
                                                  vs = f + '.' + variety;
                                                  if (!_NETInstalled.ContainsKey(vs) || v.CompareTo(_NETInstalled[vs]) > 0)
                                                      _NETInstalled[vs] = v;
                                              }
                                      }
                                  }
                              }
                          }
                      }
                  } // static void FillNetInstalled()
          
                  public static Version NETInstalled
                  {
                      get
                      {
                          FillNetInstalled();
                          return _NETInstalled[_NETInstalled.Keys[_NETInstalled.Count-1]];
                      }
                  } // NETInstalled
          
                  public static Version NET
                  {
                      get
                      {
                          FillNetInstalled();
                          string
                              clr = String.Format("{0}.{1}", Environment.Version.Major, Environment.Version.Minor);
                          Version
                              found = _NETInstalled[_NETInstalled.Keys[_NETInstalled.Count-1]];
                          if(_NETInstalled.ContainsKey(clr))
                              return _NETInstalled[clr];
          
                          for (int i = _NETInstalled.Count - 1; i >= 0; i--)
                              if (_NETInstalled.Keys[i].CompareTo(clr) < 0)
                                  return found;
                              else
                                  found = _NETInstalled[_NETInstalled.Keys[i]];
                          return found;
                      }
                  } // NET
              }
          

          【讨论】:

            【解决方案17】:

            从 4.5 版开始,Microsoft 更改了在注册表中存储 .NET Framework 指示器的方式。有关如何检索 .NET 框架和 CLR 版本的官方指南可以在这里找到:https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx

            我在这里包含了他们代码的修改版本,以解决您如何确定 4.5 及更高版本的 .NET 框架的赏金问题:

            using System;
            using System.Reflection;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using Microsoft.Win32;
            
            namespace stackoverflowtesting
            {
                class Program
                {
                    static void Main(string[] args)
                    {
                        Dictionary<int, String> mappings = new Dictionary<int, string>();
            
                        mappings[378389] = "4.5";
                        mappings[378675] = "4.5.1 on Windows 8.1";
                        mappings[378758] = "4.5.1 on Windows 8, Windows 7 SP1, and Vista";
                        mappings[379893] = "4.5.2";
                        mappings[393295] = "4.6 on Windows 10";
                        mappings[393297] = "4.6 on Windows not 10";
            
                        using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\"))
                        {
                            int releaseKey = Convert.ToInt32(ndpKey.GetValue("Release"));
                            if (true)
                            {
                                Console.WriteLine("Version: " + mappings[releaseKey]);
                            }
                        }
                        int a = Console.Read();
                    }
                }
            }
            

            【讨论】:

            • updates 用于 NET Framework 4.7NET Framework 4.7.1 ?
            【解决方案18】:

            这是我找到的解决方案:

            private static string GetDotNetVersion()
            {
              var v4 = (string)Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full", false)?.GetValue("Version");
              if(v4 != null)
                return v4;
              var v35 = (string)Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5", false)?.GetValue("Version");
              if(v35 != null)
                return v35;
              var v3 = (string)Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0", false)?.GetValue("Version");
              return v3 ?? "< 3";
            }
            

            【讨论】:

              【解决方案19】:
                      public static class DotNetHelper
              {
                  public static Version InstalledVersion
                  {
                      get
                      {
                          string framework = null;
              
                          try
                          {
                              using (var ndpKey =
                          Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\"))
                              {
                                  if (ndpKey != null)
                                  {
                                      var releaseKey = ndpKey.GetValue("Release");
                                      if (releaseKey != null)
                                      {
                                          framework = CheckFor45PlusVersion(Convert.ToInt32(releaseKey));
                                      }
                                      else
                                      {
                                          string[] versionNames = null;
                                          using (var installedVersions =
                                              Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP"))
                                          {
                                              if (installedVersions != null) versionNames = installedVersions.GetSubKeyNames();
                                          }
              
              
                                          try
                                          {
                                              if (versionNames != null && versionNames.Length > 0)
                                              {
                                                  framework = versionNames[versionNames.Length - 1].Remove(0, 1);
                                              }
                                          }
                                          catch (FormatException)
                                          {
              
                                          }
                                      }
                                  }
                              }
                          }
                          catch (SecurityException)
                          {
                          }
              
                          return framework != null ? new Version(framework) : null;
                      }
                  }
              
                  private static string CheckFor45PlusVersion(int releaseKey)
                  {
                      if (releaseKey >= 460798)
                          return "4.7";
                      if (releaseKey >= 394802)
                          return "4.6.2";
                      if (releaseKey >= 394254)
                          return "4.6.1";
                      if (releaseKey >= 393295)
                          return "4.6";
                      if (releaseKey >= 379893)
                          return "4.5.2";
                      if (releaseKey >= 378675)
                          return "4.5.1";
                      // This code should never execute. A non-null release key should mean
                      // that 4.5 or later is installed.
                      return releaseKey >= 378389 ? "4.5" : null;
                  }
              }
              

              【讨论】:

              • updates 用于 NET Framework 4.7NET Framework 4.7.1 ?
              【解决方案20】:

              如果您的计算机已连接到 Internet,请转到 smallestdotnet,下载并执行 .NET Checker 可能是最简单的方法。

              如果您需要确定版本的实际方法,请查看其在 github 上的 source,尤其是。 Constants.cs 将为您提供 .net 4.5 及更高版本的帮助,其中 Revision 部分是相关的:

                                         { int.MinValue, "4.5" },
                                         { 378389, "4.5" },
                                         { 378675, "4.5.1" },
                                         { 378758, "4.5.1" },
                                         { 379893, "4.5.2" },
                                         { 381029, "4.6 Preview" },
                                         { 393273, "4.6 RC1" },
                                         { 393292, "4.6 RC2" },
                                         { 393295, "4.6" },
                                         { 393297, "4.6" },
                                         { 394254, "4.6.1" },
                                         { 394271, "4.6.1" },
                                         { 394747, "4.6.2 Preview" },
                                         { 394748, "4.6.2 Preview" },
                                         { 394757, "4.6.2 Preview" },
                                         { 394802, "4.6.2" },
                                         { 394806, "4.6.2" },
              

              【讨论】:

              • updates 用于 NET Framework 4.7NET Framework 4.7.1 ?
              • @Kiquenet 不幸的是 4.7 和 4.7.1 未包含在源代码中,但您可以使用 issues for release keys - 和/或自己提供拉取请求 ;-)
              • PS:在你花时间进行拉取请求之前,要知道至少有一个 PR 正在等待一段时间 - 我猜 Scott 最近太忙了。
              【解决方案21】:

              我发现使用Version 类更容易:

              using Microsoft.Win32;
              using System.Runtime.InteropServices;
              
              namespace System.Runtime.InteropServices {
                public static class RuntimeInformationEx {
              
                  public static Version? GetDotnetFrameworkVersion() {
                    using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full");
                    if (key is object) {
                      if (!Int32.TryParse(key.GetValue("Release", "").ToString(), out var release)) return null;
                      return release switch
                      {
                        378389 => new Version(4, 5, 0),
                        378675 => new Version(4, 5, 1),
                        378758 => new Version(4, 5, 1),
                        379893 => new Version(4, 5, 2),
                        393295 => new Version(4, 6, 0),
                        393297 => new Version(4, 6, 0),
                        394254 => new Version(4, 6, 1),
                        394271 => new Version(4, 6, 1),
                        394802 => new Version(4, 6, 2),
                        394806 => new Version(4, 6, 2),
                        460798 => new Version(4, 7, 0),
                        460805 => new Version(4, 7, 0),
                        461308 => new Version(4, 7, 1),
                        461310 => new Version(4, 7, 1),
                        461808 => new Version(4, 7, 2),
                        461814 => new Version(4, 7, 2),
                        528040 => new Version(4, 8, 0),
                        528209 => new Version(4, 8, 0),
                        528049 => new Version(4, 8, 0),
                        _ => null
                      };
              
                    } else { // .NET version < 4.5
                      using var key1 = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP");
                      if (key1 is null) return null;
                      var parts = key1.GetSubKeyNames()[^1].Substring(1).Split('.'); // get lastsub key, remove 'v' prefix, and split
                      if (parts.Length == 2) parts = new string[] { parts[0], parts[1], "0" };
                      if (parts.Length != 3) return null;
                      Func<string, int> Parse = s => Int32.TryParse(s, out var i) ? i : -1;
                      try { return new Version(Parse(parts[0]), Parse(parts[1]), Parse(parts[2])); } catch { return null; }
                    }
                  }
              
                  public static Version? GetDotnetCoreVersion() {
                    if (!RuntimeInformation.FrameworkDescription.StartsWith(".NET Core ")) return null;
                    var parts = RuntimeInformation.FrameworkDescription.Substring(10).Split('.');
                    if (parts.Length == 2) parts = new string[] { parts[0], parts[1], "0" };
                    if (parts.Length != 3) return null;
                    Func<string, int> Parse = s => Int32.TryParse(s, out var i) ? i : -1;
                    try { return new Version(Parse(parts[0]), Parse(parts[1]), Parse(parts[2])); } catch { return null; }
                  }
                }
              }
              

              (代码为 C#8)

              【讨论】:

              • 两年前的 This answer 已经完成了从 "Release" 值到 Versions 的映射。我认为这些信息存储在注册表中的关键点以及此处详细记录的格式;无论是作为stringintenum 还是Version 呈现给调用者,都只是对同一事物进行了不同的包装。
              • 是的,据我所知,我的答案与那个答案相同,但在一个函数中包含所有 .NET 版本.. 使用版本允许轻松比较等,即var v=RuntimeInformationEx .GetDotnetFrameworkVersion(); if (v&lt;new Version(4,8,0) ...
              【解决方案22】:

              适合那些寻找所有 .net 相关版本的人。

              我结合了 .net core+framework 的相关信息。

              namespace DotNetVersions
              {
                  class Program
                  {
                      static void Main(string[] args)
                      {
                          Console.WriteLine("Currently installed \"classic\" .NET Versions in the system:");
              
                          //Show all the installed versions
                          Get1To45VersionFromRegistry();
                          Get45PlusFromRegistry();
              
              
                          Process p = new Process();
                          p.StartInfo = new ProcessStartInfo()
                          {
                              FileName = "powershell.exe",
                              Arguments = $"dotnet --info",
                              UseShellExecute = false,
                              CreateNoWindow = true,
                              RedirectStandardOutput = true,
                          };
                          p.Start();
                          string output = p.StandardOutput.ReadToEnd();
                          p.WaitForExit();
                          Console.WriteLine(output);
                      }
              
                      //Writes the version
                      private static void WriteVersion(string version, string spLevel = "")
                      {
                          version = version.Trim();
                          if (string.IsNullOrEmpty(version))
                              return;
              
                          string spLevelString = "";
                          if (!string.IsNullOrEmpty(spLevel))
                              spLevelString = " Service Pack " + spLevel;
              
                          Console.WriteLine($"{version}{spLevelString}");
                      }
                      private static void Get1To45VersionFromRegistry()
                      {
                          // Opens the registry key for the .NET Framework entry.
                          using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
                          {
                              foreach (string versionKeyName in ndpKey.GetSubKeyNames())
                              {
                                  // Skip .NET Framework 4.5 version information.
                                  if (versionKeyName == "v4")
                                  {
                                      continue;
                                  }
              
                                  if (versionKeyName.StartsWith("v"))
                                  {
              
                                      RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                                      // Get the .NET Framework version value.
                                      string name = (string)versionKey.GetValue("Version", "");
                                      // Get the service pack (SP) number.
                                      string sp = versionKey.GetValue("SP", "").ToString();
              
                                      // Get the installation flag, or an empty string if there is none.
                                      string install = versionKey.GetValue("Install", "").ToString();
                                      if (string.IsNullOrEmpty(install)) // No install info; it must be in a child subkey.
                                          WriteVersion(name);
                                      else
                                      {
                                          if (!(string.IsNullOrEmpty(sp)) && install == "1")
                                          {
                                              WriteVersion(name, sp);
                                          }
                                      }
                                      if (!string.IsNullOrEmpty(name))
                                      {
                                          continue;
                                      }
                                      foreach (string subKeyName in versionKey.GetSubKeyNames())
                                      {
                                          RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                                          name = (string)subKey.GetValue("Version", "");
                                          if (!string.IsNullOrEmpty(name))
                                              sp = subKey.GetValue("SP", "").ToString();
              
                                          install = subKey.GetValue("Install", "").ToString();
                                          if (string.IsNullOrEmpty(install)) //No install info; it must be later.
                                              WriteVersion(name);
                                          else
                                          {
                                              if (!(string.IsNullOrEmpty(sp)) && install == "1")
                                              {
                                                  WriteVersion(name, sp);
                                              }
                                              else if (install == "1")
                                              {
                                                  WriteVersion(name);
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                      }
                      private static void Get45PlusFromRegistry()
                      {
                          const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
              
                          using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(subkey))
                          {
                              if (ndpKey == null)
                                  return;
                              //First check if there's an specific version indicated
                              if (ndpKey.GetValue("Version") != null)
                              {
                                  WriteVersion(ndpKey.GetValue("Version").ToString());
                              }
                              else
                              {
                                  if (ndpKey != null && ndpKey.GetValue("Release") != null)
                                  {
                                      WriteVersion(
                                          CheckFor45PlusVersion(
                                                  (int)ndpKey.GetValue("Release")
                                              )
                                      );
                                  }
                              }
                          }
              
                          // Checking the version using >= enables forward compatibility.
                          string CheckFor45PlusVersion(int releaseKey)
                          {
                              if (releaseKey >= 528040)
                                  return "4.8";
                              if (releaseKey >= 461808)
                                  return "4.7.2";
                              if (releaseKey >= 461308)
                                  return "4.7.1";
                              if (releaseKey >= 460798)
                                  return "4.7";
                              if (releaseKey >= 394802)
                                  return "4.6.2";
                              if (releaseKey >= 394254)
                                  return "4.6.1";
                              if (releaseKey >= 393295)
                                  return "4.6";
                              if (releaseKey >= 379893)
                                  return "4.5.2";
                              if (releaseKey >= 378675)
                                  return "4.5.1";
                              if (releaseKey >= 378389)
                                  return "4.5";
                              // This code should never execute. A non-null release key should mean
                              // that 4.5 or later is installed.
                              return "";
                          }
                      }
                  }
              }
              

              示例输出,

              Currently installed "classic" .NET Versions in the system:
              2.0.50727.4927 Service Pack 2
              3.0.30729.4926 Service Pack 2
              3.5.30729.4926 Service Pack 1
              4.0.0.0
              4.8.03761
              .NET SDK (reflecting any global.json):
               Version:   5.0.102
               Commit:    71365b4d42
              
              Runtime Environment:
               OS Name:     Windows
               OS Version:  10.0.17134
               OS Platform: Windows
               RID:         win10-x64
               Base Path:   C:\Program Files\dotnet\sdk\5.0.102\
              
              Host (useful for support):
                Version: 5.0.2
                Commit:  cb5f173b96
              
              .NET SDKs installed:
                1.1.10 [C:\Program Files\dotnet\sdk]
                2.1.202 [C:\Program Files\dotnet\sdk]
                2.1.402 [C:\Program Files\dotnet\sdk]
                2.1.518 [C:\Program Files\dotnet\sdk]
                3.0.100 [C:\Program Files\dotnet\sdk]
                5.0.102 [C:\Program Files\dotnet\sdk]
              
              .NET runtimes installed:
                Microsoft.AspNetCore.All 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
                Microsoft.AspNetCore.All 2.1.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
                Microsoft.AspNetCore.All 2.1.24 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
                Microsoft.AspNetCore.All 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
                Microsoft.AspNetCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.AspNetCore.App 2.1.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.AspNetCore.App 2.1.24 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.AspNetCore.App 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.AspNetCore.App 3.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.AspNetCore.App 5.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
                Microsoft.NETCore.App 1.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 1.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 2.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 2.1.24 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 3.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.NETCore.App 5.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
                Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
                Microsoft.WindowsDesktop.App 3.1.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
                Microsoft.WindowsDesktop.App 5.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
              
              To install additional .NET runtimes or SDKs:
                https://aka.ms/dotnet-download
              

              【讨论】:

                【解决方案23】:

                试试这个:

                string GetFrameWorkVersion()
                    {
                        return System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion();
                    }
                

                【讨论】:

                • 这是给2.0,即使它与3.5一起运行
                • RuntimeEnvironment.GetSystemVersion() 似乎返回的是 CLR 版本,而不是 .NET 版本。 MSDN Page
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-10-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-10-05
                • 1970-01-01
                • 2011-06-05
                相关资源
                最近更新 更多