@@ -2811,7 +2811,7 @@ public int GetHashCode(AssemblyName obj)
28112811#if ( NET48_OR_GREATER || ! NETFRAMEWORK )
28122812 var trustedAssemblies = AppContext . GetData ( "TRUSTED_PLATFORM_ASSEMBLIES" ) as string ;
28132813#else
2814- var trustedAssemblies = "" ;
2814+ var trustedAssemblies = "" ;
28152815#endif
28162816 if ( ! string . IsNullOrEmpty ( trustedAssemblies ) )
28172817 {
@@ -2826,69 +2826,6 @@ public int GetHashCode(AssemblyName obj)
28262826 return names ;
28272827 } ) ;
28282828
2829-
2830-
2831- // // Cache for all runtime library assembly names, loaded once on demand.
2832- // private static readonly Lazy<List<AssemblyName>> _runtimeAssemblyNames = new(() =>
2833- // {
2834- // var names = new List<AssemblyName>();
2835-
2836- // try
2837- // {
2838- // // DependencyContext.Default can be null in some scenarios (like unit tests or static initializers).
2839- // // Loading the context from a known assembly is more robust.
2840-
2841- // var entryAssembly = Assembly.GetEntryAssembly() ?? typeof(RT).Assembly;
2842- // var context = Microsoft.Extensions.DependencyModel.DependencyContext.Load(entryAssembly);
2843-
2844- // if (context != null)
2845- // {
2846- // foreach (var lib in context.RuntimeLibraries)
2847- // {
2848- // foreach (var assembly in lib.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths))
2849- // {
2850- // try
2851- // {
2852- // var name = new AssemblyName(Path.GetFileNameWithoutExtension(assembly));
2853- // names.Add(name);
2854- // }
2855- // catch { }
2856- // }
2857- // }
2858- // }
2859- // }
2860- // catch { }
2861-
2862- // // Also include shared runtime libraries from TRUSTED_PLATFORM_ASSEMBLIES
2863- // try
2864- // {
2865- //#if (NET48_OR_GREATER || !NETFRAMEWORK)
2866- // var trustedAssemblies = AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") as string;
2867- //#else
2868- // var trustedAssemblies = "";
2869- //#endif
2870- // if (!string.IsNullOrEmpty(trustedAssemblies))
2871- // {
2872- // var paths = trustedAssemblies.Split(Path.PathSeparator);
2873- // foreach (var path in paths)
2874- // {
2875- // try
2876- // {
2877- // var name = AssemblyName.GetAssemblyName(path);
2878- // if (!names.Any(n => n.Name == name.Name))
2879- // {
2880- // names.Add(name);
2881- // }
2882- // }
2883- // catch { }
2884- // }
2885- // }
2886- // }
2887- // catch { }
2888-
2889- // return names;
2890- // });
2891-
28922829 internal static readonly char [ ] _triggerTypeChars = [ '`' , ',' , '[' , '&' , '*' ] ;
28932830
28942831 public static Type classForName ( string p )
@@ -2952,50 +2889,69 @@ internal static Type classForName(string p, Namespace ns, bool canCallClrTypeSpe
29522889 }
29532890 }
29542891
2892+
29552893 // Try to load from runtime libraries if we have DependencyContext.
2894+ // We might use the parsed name again, so save it here for use now and below.
2895+
2896+ var parsedTypename = ClrTypeSpec . Parse ( p ) ;
2897+
29562898 {
29572899 // Split the type name to identify the namespace and simple name.
2958- string namespaceName = null ;
2959- string typeName = p ;
2960- int lastDot = p . LastIndexOf ( '.' ) ;
2961- if ( lastDot > 0 )
2900+ // If we get something like
2901+ // System.Collections.Concurrent.ConcurrentDictionary`2[System.Object,System.Object]
2902+ // we want to extract System.Collections.Concurrent as the namespace.
2903+ // Worst case: we do a ClrTypeSpec.Parse and extract the namespace from there.
2904+ // Easier, but I won't guarantee it: move forward as long as we don't run into back characters, then back up to the last dot.
2905+
2906+ string assemblyNameString = null ;
2907+
2908+ if ( ! string . IsNullOrWhiteSpace ( parsedTypename . AssemblyName ) )
2909+ assemblyNameString = parsedTypename . AssemblyName ;
2910+ else
29622911 {
2963- namespaceName = p . Substring ( 0 , lastDot ) ;
2964- typeName = p . Substring ( lastDot + 1 ) ;
2912+ var baseName = parsedTypename . Name . DisplayName ; // Note: this does not include nested.
2913+ int lastDot = baseName . LastIndexOf ( '.' ) ;
2914+ if ( lastDot > 0 )
2915+ assemblyNameString = baseName . Substring ( 0 , lastDot ) ;
2916+ // If there is no dot, no point in moving forward. just leave assemblyNameString == null;].
29652917 }
29662918
2967- if ( ! string . IsNullOrEmpty ( namespaceName ) )
2919+ if ( ! string . IsNullOrEmpty ( assemblyNameString ) )
29682920 {
29692921 var runtimeAssemblyNames = _runtimeAssemblyNames . Value ;
29702922
2971- var targetAssemblyName = new AssemblyName ( namespaceName ) ;
2972-
2973- // try if the namespace directly matches the assembly name.
2974- if ( runtimeAssemblyNames . TryGetValue ( targetAssemblyName , out var path ) )
2923+ try
29752924 {
2925+ var targetAssemblyName = new AssemblyName ( assemblyNameString ) ;
29762926
2977- if ( loadedAssemblies . Any ( a => a . GetName ( ) . Name . Equals ( namespaceName , StringComparison . OrdinalIgnoreCase ) ) )
2927+ // try if the namespace directly matches the assembly name.
2928+ if ( runtimeAssemblyNames . TryGetValue ( targetAssemblyName , out var path ) )
29782929 {
2979- // Skip if this assembly is already loaded.
2980- }
2981- else
2982- {
2983- NumRuntimeAssemblyLoads ++ ;
2984- var assy = string . IsNullOrWhiteSpace ( path ) ? Assembly . Load ( targetAssemblyName ) : Assembly . LoadFrom ( path ) ;
2985- var type = assy . GetType ( p , false ) ;
2986- if ( type != null && ( type . IsPublic || type . IsNestedPublic ) )
2930+
2931+ if ( loadedAssemblies . Any ( a => a . GetName ( ) . Name . Equals ( assemblyNameString , StringComparison . OrdinalIgnoreCase ) ) )
2932+ {
2933+ // Skip if this assembly is already loaded.
2934+ }
2935+ else
29872936 {
2988- NumRuntimeAssemblyFinds ++ ;
2989- return type ;
2937+ NumRuntimeAssemblyLoads ++ ;
2938+ var assy = string . IsNullOrWhiteSpace ( path ) ? Assembly . Load ( targetAssemblyName ) : Assembly . LoadFrom ( path ) ;
2939+ var type = assy . GetType ( p , false ) ;
2940+ if ( type != null && ( type . IsPublic || type . IsNestedPublic ) )
2941+ {
2942+ NumRuntimeAssemblyFinds ++ ;
2943+ return type ;
2944+ }
29902945 }
29912946 }
29922947 }
2948+ catch
2949+ {
2950+ // Ignore failures to load assembly.
2951+ }
29932952 }
29942953 }
29952954
2996-
2997-
2998-
29992955 // Search by simple type name (slow path).
30002956 // At some point this became a no-op unless running on Mono, so I restricted it to that.
30012957 if ( IsRunningOnMono )
@@ -3044,7 +3000,7 @@ internal static Type classForName(string p, Namespace ns, bool canCallClrTypeSpe
30443000
30453001 if ( canCallClrTypeSpec )
30463002 {
3047- var t1 = ClrTypeSpec . GetTypeFromName ( p , ns ) ;
3003+ var t1 = ClrTypeSpec . GetTypeFromParsedName ( parsedTypename , ns ) ;
30483004 if ( t1 is not null )
30493005 {
30503006 NumParsing ++ ;
0 commit comments