如何在运行时检测 .NET 4.5 版当前正在运行您的代码?

Posted

技术标签:

【中文标题】如何在运行时检测 .NET 4.5 版当前正在运行您的代码?【英文标题】:How do I detect at runtime that .NET version 4.5 is currently running your code? 【发布时间】:2012-01-20 23:25:19 【问题描述】:

我从 http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27541 安装了 .NET 4.5 Developer preview,它“替换”了 .NET 4.0 版本。

但是,检测 .NET 框架版本的旧方法似乎返回 4.0(更准确地说是我的 PC 上的 4.0.30319.17020),而不是 4.5(肯定可能是为了向后兼容,或者?):

using System;

namespace ConsoleApplication

    class Program
    
        static void Main(string[] args)
        
            var version = Environment.Version;
            Console.WriteLine(version.ToString());
            Console.ReadKey();
        
    

如何检测我的代码是否真的由 .NET 4.5 执行?

【问题讨论】:

没有“CLR 4.5”,仍然使用CLR 4.0.30319版本。 @tobias86:.NET 4.5 不同。它取代了您 PC 上的 .NET 4.0! :) 好吧,把点连起来,你问题的最后一句话因此无法回答。唯一合乎逻辑的事情是检查是否安装了 4.5。如果是,那么 4.0 版本就无法执行您的程序。 HansPassant, CodyGray:我们假设,我安装了 .NET 4.5,但现在很困惑是它真的有效还是在安装过程中出了什么问题,我仍然使用 .NET 4.0(对于 Windows 应用程序,尤其是 ASP.NET 应用程序)。 NET MVC 主机)。我不想做 GC 基准测试或使用“功能检测”(参见 Christian.K 的回答)来了解执行我的代码的运行时。 .NET 4.5 引入了大量改进/新功能,让我感到困惑的是,无法检测它执行的代码(不是检测安装的 v4.5,这很简单,但它实际上可以工作!)。 @EverQ 我并没有试图把话放在你的嘴里或做出任何假设(因此我说“你仍然没有似乎......”)。如果您有任何冒犯,请对此深表歉意。无论如何,关于您的示例,您可以确定新的 CLR(即使它附带 .NET 4.5,它显然仍然是 v4.0)。下面给出示例。 【参考方案1】:

根据我从在线资源中了解到的情况,.NET 4.5 的行为方式与 3.5 对 2.0 的行为方式相似(尽管不完全相同):您的版本号保持不变(如果您运行 3.5 代码,CLR 版本将为2.0),它将作为现有 CLR 4.0 的更新。

因此,您将能够将共存的 2.0 升级到 3.5,并将 4.0 升级到 4.5。

尚不清楚的是,是否可以在 4.0 中制作(或处理现有)项目而无需将它们升级到 4.5:目前您可以在 Visual Studio 2010 中制作 2.0 或 3.5 项目,但也许不会4.0 和 4.5 相同。

【讨论】:

您只需为 .NET 4.0 编译您的项目,据我所知,它会自动在 .NET 4.5 下运行(确定您的 PC 上是否安装了 .NET 4.5)。但是目前还不清楚如何在运行时检测到它!【参考方案2】:

您需要明确区分 CLR(即“运行时”)和框架库(即“框架”)。您在第一个或第一个上执行您的代码,您的代码被编译并使用后者。不幸的是,当使用术语“.NET 版本”时,通常指的是运行时和框架的整个包,而不管它们各自的版本如何——如前所述——可能不同。

您可以检测到installed framework versions。但是,这并不能告诉您在运行时实际使用的是哪一个。

我不确定 4.5,但 2.0 与 3.0 或 3.5 Environment.Version 没有任何帮助,因为它总是返回 2.0,因为所有这些框架版本都使用 CLR 2.0。我假设对于 framework 4.5,CLR 版本仍然是 4.0,这可以解释即使在这种情况下Environment.Version 返回 4.0.x。

一种可能对您有用的技术是检查核心库(mscorlib、System.Core 等)中的类型、方法或属性,您知道这些库仅从特定的 .NET 框架版本开始存在。

例如,ReflectionContext 类在 .NET 框架 4.5 中似乎是全新的,并且可以方便地使用 mscorlib。所以你可以做这样的事情。

  public static bool IsNet45OrNewer()
  
      // Class "ReflectionContext" exists from .NET 4.5 onwards.
      return Type.GetType("System.Reflection.ReflectionContext", false) != null;
  

说了这么多,人们可能会质疑为什么您需要知道您使用的是哪个 .NET 版本。只需尝试访问您需要的功能,如果它们不存在,可能会优雅地回退到其他东西(旧版本中可用)。

更新:请注意,术语 .NET 4.5 是指组成基类库 (BCL) 和更多(统称为“框架”)的几个程序集以及运行时本身的整个包,即 CLR - 两者都可以有不同的版本,如前所述。

我不为 Microsoft 工作,并且不了解缺少(单一)函数或 API 来获得“.NET 框架版本”的真正原因,但我可以做出有根据的猜测。

    尚不清楚此类函数/API 应提供哪些信息。 甚至 BCL 的各个程序集也不共享通用(程序集/文件)版本。例如,对于 .NET 3.0 和 3.5,mscorlib.dll 的版本为 2.0.x,而只有 WCF 和 WF 的新程序集有 3.0 版本。我认为即使使用 .NET 3.5,System.ServiceModel.dll 仍然有 3.0.x 版本。我想说的是,框架的所有程序集上都没有统一的版本。那么像System.Environment.FrameworkVersionreturn 这样的 API 调用应该是什么?该版本的价值是什么(即使它确实返回了像 4.5 这样的“符号”版本,它也没有什么价值,不是吗?)。

    过于具体一些新功能可能会出现在现有版本的 SP 中,并且是新版本的一部分。进行功能检查时,您的应用程序可能在 以前 已更新的版本上运行良好,而通过显式版本检查,它可能会不必要地将自身限制为最新版本。我没有来自 .NET 世界的示例,但总的来说(以及在 Windows 本身中,例如 WMI)它可以而且确实发生了。

    不想要。我可以想象,确定应用程序当前正在使用的“框架版本”的方法甚至是不理想的为他们提供。在本机/Win32 世界中,version checking fallacies 有着悠久而邪恶的历史(有关适用于 .NET 的概念,请参见“不检查版本”段落)。例如,人们错误地使用了GetVersionGetVersionEx API,只检查他们运行的版本是否是他们在编写应用程序时知道的最新版本。因此,当应用程序在较新版本的 Windows 上运行时,它不会运行,即使它们真正使用的 功能 仍然存在。微软可能已经考虑过类似的问题,因此甚至没有在 .NET 中提供一些 API。

顺便说一句,这是微软recommends在GetVersion函数的备注部分:

识别当前操作系统通常不是最好的方法 以确定是否存在特定的操作系统功能。 这是因为操作系统可能添加了新功能 在可再发行的 DLL 中。而不是使用 GetVersionEx 来确定 操作系统平台或版本号,测试是否存在 功能本身。

Windows 团队博客也有一些关于此的 to say。

我知道这一切都是关于 Windows 和本机编程的,但对于 .NET 应用程序、框架和 CLR 而言,概念和危险是相同的。

我会说使用(优雅的)回退进行功能检查是一种更加可靠和健壮的方式,可以确保您的应用程序向下兼容。如果您只希望您的应用程序与特定版本的 .NET 或更高版本一起使用,请不要做任何特别的事情,并依靠 .NET 本身的向后兼容性。

【讨论】:

当然,感谢您的回答!我也在考虑“modernizr”方法 :),但是 javascript 检测功能的方法在 .NET 中并不常见 :) 如果继续你的回答,除了“优雅地回退”之外,接下来可能会是使用一些“polyfill”来替代 .NET 4.5 功能:D 等。我只是认为 MSFT 应该有其他方法来检测哪个运行时版本执行代码 :) 我建议大家也阅读 Scott Hanselman 的以下博客文章:hanselman.com/blog/…。特别是我喜欢将 添加到几乎任何应用程序类型的 app.config 中的想法,如果您的应用程序需要 .NET,则 ASP.NET 除外4.5 运行时。 (如果 .NET 4.5 不可用,用户将被提升安装)。但是,这并不完全是检测:(...无论如何,我 +1 询问 ASP.NET 团队是否也可以添加对此类配置参数的支持。 只是想添加我的理由来检查是否安装了 .net 4.5 框架:***.com/a/15715990/423356(MemoryCache.Default 在 Web 应用程序错误上得到处理) @kite 是的,正是这种情况,当您可以检测到 .NET 版本并在需要时应用一些解决方法时:) 好点,谢谢。然而,再次认为检测 .NET 版本应该比现在在这里选择的正确答案更容易......特别是对于这种检测应该足够快的情况(上面的解决方案使用反射,所以更好地确保您将 IsNet45OrNewer 存储在第一次检测后的一些静态属性并使用它而不是调用内部反射的方法)。 更新 .NET 4.5.1:如果您需要检查最新的 .NET Framework 版本 4.5.1,请随意使用其中引入的另一种类型(枚举)版本:System.Runtime.GCLargeObjectHeapCompactionMode,例如:Type.GetType("System.Runtime.GCLargeObjectHeapCompactionMode", false) != null【参考方案3】:

.NET Framework 4.5 是对 4.0 的就地升级。这大致意味着如果您在 4.0 或 4.5 运行时版本上运行,并且安装了 4.5,那么您肯定在 4.5 上运行。您的检查可能如下所示。

让我们同时调用 4.0 和 4.5 运行时 4.0 版本的运行时

    检查您是否在 4.0 版本的运行时上运行:

    如果您的程序集编译为面向 .NET 4.0,或者 Environment.Version.Major == 4 && Environment.Version.Minor == 0

    那么您在 4.0 版本的运行时上运行。

    通过检查安装的版本来检查您的 4.0 版本的运行时实际上是 4.0 还是 4.5:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client 键下,检查_Version_ 值。如果它以"4.0" 开头,则表示您在 4.0 运行时上运行,如果它以 "4.5" 开头,则表示您在 4.5 运行时上运行。

【讨论】:

【参考方案4】:

您可以通过检查注册表中的 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full 子项的 DWORD 值来测试是否安装了 .NET Framework 4.5.NET Framework 4命名为Release。此DWORD 的存在表明该计算机上已安装.NET Framework 4.5Release 的值是版本号。要确定是否安装了 .NET Framework 4.5 的最终发行版,请检查是否有等于或大于 378389 的值。

【讨论】:

Christian.K 的注册表项和 IsNet45OrNewer() 函数非常完美。谢谢,@Vipul! 来自 MSDN 关于此注册表值:msdn.microsoft.com/en-us/library/hh925568.aspx '''您必须拥有管理凭据才能运行此示例''' 这不能回答问题【参考方案5】:

要准确确定您的应用程序正在运行哪个 .NET 补丁,请进行此调用以查找 mscorlib 的内部版本号:

System.Diagnostics.FileVersionInfo.GetVersionInfo(typeof(int).Assembly.Location).ProductVersion

它目前为我返回 4.6.1055.0,它对应于 .NET 4.6.1。

【讨论】:

不错的方法并且很容易实现。但是是否有该值的可能值列表,以便我们可以将版本号与特定框架匹配? @Alejandro 我不知道有一个。但是,您可能不应该尝试从这个数字向后工作,因为对于同一个“营销”版本的框架会存在多个补丁。 @JamesL 当然,但这可以通过与预期版本号进行范围比较来轻松考虑,涵盖每个主要版本的所有可能补丁。到目前为止,这种方法是我能找到的唯一方法来获得实际执行的确切运行时。 谢谢你。鉴于缺乏任何其他可靠的方式来查找运行时,您的回答被低估了。鉴于最近框架发布的质量下降,在尝试诊断模糊的客户端错误时,这一点变得越来越重要。 该死!看起来很可爱,但在我需要了解的托管环境中引发了 System.Security.SecurityException。 :(【参考方案6】:

James 提供了great answer 在运行时获取 mscorlib.dll 的“产品版本”:

(using System.Diagnostics;)

FileVersionInfo.GetVersionInfo(typeof(int).Assembly.Location).ProductVersion

这很好用,但您可以通过检查 System.dll 来获得更细粒度的结果:

FileVersionInfo.GetVersionInfo(typeof(Uri).Assembly.Location).ProductVersion

请注意,细微的差别是使用 typeof(Uri) 的程序集而不是 typeof(int),因为前者是在 System.dll 中定义的,而 mscorlib.dll 是在后者中定义的。对于一个针对 .NET 4.7.1 的简单 C# 控制台程序,目前在我的系统上报告的差异如下

...\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll 4.7.2600.0 ...\Microsoft.NET\Framework\v4.0.30319\System.dll 4.7.2556.0

至于区分是否有用或如何使用更详细的信息,这将取决于具体情况。

【讨论】:

【参考方案7】:

从 .NET Core 3.0(和 .NET Standard 2.1)开始,情况发生了变化,现在 Environment.Version 可以正常工作。所以你可以使用这个属性来检测你使用的 dot net 版本。

System.Console.WriteLine($"Environment.Version: System.Environment.Version");

// Old result
//   Environment.Version: 4.0.30319.42000
//
// New result
//   Environment.Version: 3.0.0

更多信息请参见documentation。

【讨论】:

以上是关于如何在运行时检测 .NET 4.5 版当前正在运行您的代码?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Mono 在 XSP 上运行 .NET 4.5?

XSP 可以运行 ASP.NET 4.5 吗?

如何检测正在使用哪个 .NET 运行时(MS 与 Mono)?

如何让 .NET 4.5 网站在 IIS6 上运行?

如何在 .NET 4.5 中“同时”运行这两种方法?

如何检测 Android 运行时(Dalvik 或 ART)?