9

I have a quick question: When I go to HELP->About in Visual Studio 2012, the window indicates that the version of .NET I'm using is 4.5.50709. However, when I execute the following code:

Console.WriteLine(Environment.Version);

I get version 4.0.30319.18034. What gives? In Troelsen's Pro C# 5 & .NET 4.5 Framework, on page 81 it states that the Version property returns an object representing the .NET platform version. Is this incorrect? The thread for a previous question indicated that this property returns the CLR version. If this is the case, what is the purpose of the Version object (as in, what is the use of knowing the CLR version as opposed to the framework version), and how do you actually get the framework version itself?

2 Answers2

17

The CLR (Common Language Runtime) version is 4.0.30319.18034. It starts with 4.0.30319 because .NET 4.5 is an in-place upgrade of the .NET 4.0 assemblies.

The 4.5 update completely replaces the .NET 4.0 runtime and leaves the actual version number set at v4.0.30319.

(source 1, source 2)

But your version number probably represents .NET 4.5 with some updates, as might be deduced from this list by user Daniel:

Here are some examples of runtime versions I've seen:

  • 4.0.30319.1 = .NET 4.0 RTM
  • 4.0.30319.269 = most common .NET 4.0 version we're seeing in the data collected from our users
  • 4.0.30319.544 = another .NET 4.0 version that a small portion of our users have installed
  • 4.0.30319.17626 = .NET 4.5 RC
  • 4.0.30319.17929 = .NET 4.5 RTM
  • 4.0.30319.18010 = current version on my Windows 8 machine

The major, minor and build version numbers didn't change, so I reckon they didn't think the difference between .NET 4.0 and 4.5 would be big enough to matter for most people. Applications for .NET 4.0 that expect some version 4.0.30319 still work as expected under .NET 4.5.


Whether you code for .NET 4.0 or 4.5, you are compiling against the exact same .NET assemblies. The only difference is that some new classes from .NET 4.5 are hidden when compiling against .NET 4.0 (as if they never existed). So the only reliable way to tell the difference between .NET 4.0 and 4.5 seems to be the rather hackish approach proposed by Christian.K in his post, that doesn't involve version numbers:

The ReflectionContext class seems to be totally new with the .NET framework 4.5 and conveniently lives in mscorlib. So you could do something like this.

public static bool IsNet45OrNewer()
{
    // Class "ReflectionContext" exists from .NET 4.5 onwards.
    return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
Community
  • 1
  • 1
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • That makes sense, but is there a property that actually returns the .NET version as opposed to the CLR version? And in what circumstances would you need to know the CLR version as opposed to the framework version itself? – Vincent Alegrete Apr 22 '13 at 00:28
  • The same thing happens for 2.0 - 3.5 they are all 2.0 of the CLR. – Scott Chamberlain Apr 22 '13 at 00:37
  • I really appreciate you taking the time to compile and write all that for me. It makes a lot more sense now. I guess it all stemmed from a misunderstanding on my part as to what the numbers represented. Thanks so much! – Vincent Alegrete Apr 22 '13 at 00:48
  • excellent answer, and I appreciate the links to source1 an source2. – Pyderman Aug 16 '13 at 09:52
2

Just as an exercise I was wondering how Visual Studio retrieved the .NET version. You can query the registry to see which versions are installed and I came up with this code:

static void Main(string[] args)
{
    Console.WriteLine("The following .NET versions are installed:");
    var vers = SearchRegistry(Registry.LocalMachine, "Software\\Microsoft\\NET Framework Setup\\NDP", "Version")
        .GroupBy(v => v)
        .Select(v => (string)v.Key)
        .OrderBy(s => s);

    foreach (string s in vers)
        Console.WriteLine(s);

    Console.WriteLine(string.Format("Newest Installed .NET version: {0}", vers.Last()));
}

private static IEnumerable<object> SearchRegistry(RegistryKey root, string subkey, string search)
{
    foreach (string sub in root.OpenSubKey(subkey).GetSubKeyNames())
    {
        foreach (string val in root.OpenSubKey(subkey).OpenSubKey(sub).GetValueNames())
            if (val == search)
                yield return root.OpenSubKey(subkey).OpenSubKey(sub).GetValue(val);

        foreach (var o in SearchRegistry(root.OpenSubKey(subkey), sub, search))
            yield return o;
    }
}
Joey Gennari
  • 2,361
  • 17
  • 26