1
1
using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Diagnostics ;
2
4
using System . IO ;
3
5
using System . Linq ;
6
+ using System . Reflection ;
7
+ using System . Runtime . Versioning ;
4
8
using Microsoft . Win32 ;
5
9
6
10
namespace BenchmarkDotNet . Helpers
@@ -10,15 +14,65 @@ internal static class FrameworkVersionHelper
10
14
// magic numbers come from https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
11
15
// should be ordered by release number
12
16
private static readonly ( int minReleaseNumber , string version ) [ ] FrameworkVersions =
13
- {
17
+ [
14
18
( 533320 , "4.8.1" ) , // value taken from Windows 11 arm64 insider build
15
19
( 528040 , "4.8" ) ,
16
20
( 461808 , "4.7.2" ) ,
17
21
( 461308 , "4.7.1" ) ,
18
22
( 460798 , "4.7" ) ,
19
23
( 394802 , "4.6.2" ) ,
20
24
( 394254 , "4.6.1" )
21
- } ;
25
+ ] ;
26
+
27
+ internal static string ? GetTargetFrameworkVersion ( )
28
+ {
29
+ // Search assemblies until we find a TargetFrameworkAttribute with a supported Framework version.
30
+ // We don't search all assemblies, only the entry assembly and callers.
31
+ foreach ( var assembly in EnumerateAssemblies ( ) )
32
+ {
33
+ foreach ( var attribute in assembly . GetCustomAttributes < TargetFrameworkAttribute > ( ) )
34
+ {
35
+ switch ( attribute . FrameworkName )
36
+ {
37
+ case ".NETFramework,Version=v4.6.1" : return "4.6.1" ;
38
+ case ".NETFramework,Version=v4.6.2" : return "4.6.2" ;
39
+ case ".NETFramework,Version=v4.7" : return "4.7" ;
40
+ case ".NETFramework,Version=v4.7.1" : return "4.7.1" ;
41
+ case ".NETFramework,Version=v4.7.2" : return "4.7.2" ;
42
+ case ".NETFramework,Version=v4.8" : return "4.8" ;
43
+ case ".NETFramework,Version=v4.8.1" : return "4.8.1" ;
44
+ }
45
+ }
46
+ }
47
+
48
+ return null ;
49
+
50
+ static IEnumerable < Assembly > EnumerateAssemblies ( )
51
+ {
52
+ var entryAssembly = Assembly . GetEntryAssembly ( ) ;
53
+ // Assembly.GetEntryAssembly() returns null in unit test frameworks.
54
+ if ( entryAssembly != null )
55
+ {
56
+ yield return entryAssembly ;
57
+ }
58
+ // Search calling assemblies starting from the highest stack frame
59
+ // (expected to be the entry assembly if Assembly.GetEntryAssembly() returned null),
60
+ // excluding this assembly.
61
+ var stacktrace = new StackTrace ( false ) ;
62
+ var searchedAssemblies = new HashSet < Assembly > ( )
63
+ {
64
+ stacktrace . GetFrame ( 0 ) . GetMethod ( ) . ReflectedType . Assembly
65
+ } ;
66
+ for ( int i = stacktrace . FrameCount - 1 ; i >= 1 ; -- i )
67
+ {
68
+ var assembly = stacktrace . GetFrame ( i ) . GetMethod ( ) . ReflectedType . Assembly ;
69
+ if ( searchedAssemblies . Add ( assembly ) )
70
+ {
71
+ yield return assembly ;
72
+ }
73
+ }
74
+ }
75
+ }
22
76
23
77
internal static string GetFrameworkDescription ( )
24
78
{
@@ -57,30 +111,28 @@ internal static string MapToReleaseVersion(string servicingVersion)
57
111
58
112
59
113
#if NET6_0_OR_GREATER
60
- [ System . Runtime . Versioning . SupportedOSPlatform ( "windows" ) ]
114
+ [ SupportedOSPlatform ( "windows" ) ]
61
115
#endif
62
116
private static int ? GetReleaseNumberFromWindowsRegistry ( )
63
117
{
64
- using ( var baseKey = RegistryKey . OpenBaseKey ( RegistryHive . LocalMachine , RegistryView . Registry32 ) )
65
- using ( var ndpKey = baseKey . OpenSubKey ( @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\" ) )
66
- {
67
- if ( ndpKey == null )
68
- return null ;
69
- return Convert . ToInt32 ( ndpKey . GetValue ( "Release" ) ) ;
70
- }
118
+ using var baseKey = RegistryKey . OpenBaseKey ( RegistryHive . LocalMachine , RegistryView . Registry32 ) ;
119
+ using var ndpKey = baseKey . OpenSubKey ( @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\" ) ;
120
+ if ( ndpKey == null )
121
+ return null ;
122
+ return Convert . ToInt32 ( ndpKey . GetValue ( "Release" ) ) ;
71
123
}
72
124
73
125
#if NET6_0_OR_GREATER
74
- [ System . Runtime . Versioning . SupportedOSPlatform ( "windows" ) ]
126
+ [ SupportedOSPlatform ( "windows" ) ]
75
127
#endif
76
- internal static string GetLatestNetDeveloperPackVersion ( )
128
+ internal static string ? GetLatestNetDeveloperPackVersion ( )
77
129
{
78
- if ( ! ( GetReleaseNumberFromWindowsRegistry ( ) is int releaseNumber ) )
130
+ if ( GetReleaseNumberFromWindowsRegistry ( ) is not int releaseNumber )
79
131
return null ;
80
132
81
133
return FrameworkVersions
82
- . FirstOrDefault ( v => releaseNumber >= v . minReleaseNumber && IsDeveloperPackInstalled ( v . version ) )
83
- . version ;
134
+ . FirstOrDefault ( v => releaseNumber >= v . minReleaseNumber && IsDeveloperPackInstalled ( v . version ) )
135
+ . version ;
84
136
}
85
137
86
138
// Reference Assemblies exists when Developer Pack is installed
0 commit comments