title: Future-proofing the .NET version detection
body: <p>Not to beat the <a href="https://stackoverflow.com/questions/139891/whats-the-foolproof-way-to-tell-which-versions-of-net-are-installed-on-a-prod">dead</a> <a href="https://stackoverflow.com/questions/199080/how-to-detect-what-net-framework-versions-and-service-packs-are-installed">horse</a>, however,  I am looking for a way to detect the installed .NET frameworks.  It seems like the provided solutions (in the links) are all good up until the point a new version of the framework is released and then all bets are off.  The reason for this is that the detection relies on the registry keys and it seems that v4 of the framework has broken the convention and one now has to take extra steps to detect v4.</p>
  
  <p>Is there a way to detect the .NET framework that will also work when .NET v5 appears.</p>
  
  <p>EDIT: Ok, for future generations of frustrated .NET Version seekers, here is the code to make it happen:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Text.RegularExpressions;
  using System.Diagnostics;
  using Microsoft.Win32;
  
  private List&lt;string&gt; GetInstalledDotNetFrameworks()
  {
      string key = string.Empty;
      string version = string.Empty;
      List&lt;string&gt; frameworks = new List&lt;string&gt;();
  
      var matches = Registry.LocalMachine
                  .OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP")
                  .GetSubKeyNames().Where(keyname =&gt; Regex.IsMatch(keyname, @"^v\d"));
  
  
      // special handling for v4.0 (deprecated) and v4 (has subkeys with info)
      foreach (var item in matches)
      {
          switch (item)
          {
              case "v4.0":  // deprecated - ignore
                  break;
  
              case "v4":// get more info from subkeys
  
                  key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item;
                  string[] subkeys = Registry.LocalMachine
                      .OpenSubKey(key)
                      .GetSubKeyNames();
  
  
                  foreach (var subkey in subkeys)
                  {
                      key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item + @"\" + subkey;
                      version = Registry.LocalMachine
                              .OpenSubKey(key)
                              .GetValue("Version").ToString();
  
                      version = string.Format("{0} ({1})", version, subkey);
                      frameworks.Add(version);
                  }
  
  
                  break;
              case "v1.1.4322":   // special case, as the framework does not follow convention
                  frameworks.Add(item);
                  break;
              default:
  
                  try
                  {
                      // get the Version value
                      key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item;
                      version = Registry.LocalMachine
                              .OpenSubKey(key)
                              .GetValue("Version").ToString();
  
                      frameworks.Add(version);
  
                  }
                  catch
                  {
                      // most likely new .NET Framework got introduced and broke the convention
                  }
  
                  break;
  
          }
  
      }
  
      // sort the list, just in case the registry was not sorted
      frameworks.Sort();
  
      return frameworks;
  }
  </code></pre>