diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs index ee55cf1087d2b..3bfe90d49c136 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport //========================================================================================================================== internal sealed class ConstructorPolicies : MemberPolicies { + public static readonly ConstructorPolicies Instance = new ConstructorPolicies(); + + public ConstructorPolicies() : base(MemberTypeIndex.Constructor) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Reflection implementation")] public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs index e8ba0e22ea9ae..6c5bd52835d64 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport //========================================================================================================================== internal sealed class EventPolicies : MemberPolicies { + public static readonly EventPolicies Instance = new EventPolicies(); + + public EventPolicies() : base(MemberTypeIndex.Event) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Reflection implementation")] public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) @@ -67,7 +71,7 @@ public sealed override bool ImplicitlyOverrides(EventInfo? baseMember, EventInfo { MethodInfo? baseAccessor = GetAccessorMethod(baseMember!); MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!); - return MemberPolicies.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor); + return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor); } public sealed override bool OkToIgnoreAmbiguity(EventInfo m1, EventInfo m2) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs index a1fe8f0c069e7..6447680dc6ea1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport //========================================================================================================================== internal sealed class FieldPolicies : MemberPolicies { + public static readonly FieldPolicies Instance = new FieldPolicies(); + + public FieldPolicies() : base(MemberTypeIndex.Field) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Reflection implementation")] public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs index 50a665e5aea3a..e8c5ca8efee76 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs @@ -15,6 +15,11 @@ namespace System.Reflection.Runtime.BindingFlagSupport //================================================================================================================= internal abstract class MemberPolicies where M : MemberInfo { + public MemberPolicies(int index) + { + Index = index; + } + //================================================================================================================= // Subclasses for specific MemberInfo types must override these: //================================================================================================================= @@ -184,55 +189,11 @@ private static bool GenericMethodAwareAreParameterTypesEqual(Type t1, Type t2) return false; } - static MemberPolicies() - { - Type t = typeof(M); - if (t.Equals(typeof(FieldInfo))) - { - MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Field; - Default = (MemberPolicies)(object)(new FieldPolicies()); - } - else if (t.Equals(typeof(MethodInfo))) - { - MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Method; - Default = (MemberPolicies)(object)(new MethodPolicies()); - } - else if (t.Equals(typeof(ConstructorInfo))) - { - MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Constructor; - Default = (MemberPolicies)(object)(new ConstructorPolicies()); - } - else if (t.Equals(typeof(PropertyInfo))) - { - MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Property; ; - Default = (MemberPolicies)(object)(new PropertyPolicies()); - } - else if (t.Equals(typeof(EventInfo))) - { - MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Event; - Default = (MemberPolicies)(object)(new EventPolicies()); - } - else if (t.Equals(typeof(Type))) - { - MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.NestedType; - Default = (MemberPolicies)(object)(new NestedTypePolicies()); - } - else - { - Debug.Fail("Unknown MemberInfo type."); - } - } - - // - // This is a singleton class one for each MemberInfo category: Return the appropriate one. - // - public static readonly MemberPolicies Default; - // // This returns a fixed value from 0 to MemberIndex.Count-1 with each possible type of M // being assigned a unique index (see the MemberTypeIndex for possible values). This is useful // for converting a type reference to M to an array index or switch case label. // - public static readonly int MemberTypeIndex; + public int Index { get; } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs index 040034cb4e5e3..b56f748c72c2e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport //========================================================================================================================== internal sealed class MethodPolicies : MemberPolicies { + public static readonly MethodPolicies Instance = new MethodPolicies(); + + public MethodPolicies() : base(MemberTypeIndex.Method) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Reflection implementation")] public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs index 9fd791d0d655b..495ad6a93a851 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs @@ -23,6 +23,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport //========================================================================================================================== internal sealed class NestedTypePolicies : MemberPolicies { + public static readonly NestedTypePolicies Instance = new NestedTypePolicies(); + + public NestedTypePolicies() : base(MemberTypeIndex.NestedType) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Reflection implementation")] public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs index c7752043c63b9..c7eac9bb009b1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport //========================================================================================================================== internal sealed class PropertyPolicies : MemberPolicies { + public static readonly PropertyPolicies Instance = new PropertyPolicies(); + + public PropertyPolicies() : base(MemberTypeIndex.Property) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Reflection implementation")] public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) @@ -54,7 +58,7 @@ public sealed override bool ImplicitlyOverrides(PropertyInfo? baseMember, Proper { MethodInfo? baseAccessor = GetAccessorMethod(baseMember!); MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!); - return MemberPolicies.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor); + return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor); } // diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs index ed5cabdba05f1..ff09d8b9719f4 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs @@ -96,12 +96,10 @@ public QueriedMemberList Filter(Func predicate) // // Filter by name and visibility from the ReflectedType. // - public static QueriedMemberList Create(RuntimeTypeInfo type, string optionalNameFilter, bool ignoreCase) + public static QueriedMemberList Create(MemberPolicies policies, RuntimeTypeInfo type, string optionalNameFilter, bool ignoreCase) { RuntimeTypeInfo reflectedType = type; - MemberPolicies policies = MemberPolicies.Default; - NameFilter? nameFilter; if (optionalNameFilter == null) nameFilter = null; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs index 0a47c45066b13..301fe25f6fa38 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs @@ -14,8 +14,9 @@ namespace System.Reflection.Runtime.BindingFlagSupport // internal partial struct QueryResult where M : MemberInfo { - public QueryResult(BindingFlags bindingAttr, QueriedMemberList queriedMembers) + public QueryResult(MemberPolicies policies, BindingFlags bindingAttr, QueriedMemberList queriedMembers) { + _policies = policies; _lazyCount = 0; _bindingAttr = bindingAttr; _queriedMembers = queriedMembers; @@ -114,8 +115,7 @@ public void CopyTo(MemberInfo[] array, int startIndex) if (match.DeclaringType.Equals(challenger.DeclaringType)) throw new AmbiguousMatchException(); - MemberPolicies policies = MemberPolicies.Default; - if (!policies.OkToIgnoreAmbiguity(match, challenger)) + if (!_policies.OkToIgnoreAmbiguity(match, challenger)) throw new AmbiguousMatchException(); } else @@ -129,6 +129,7 @@ public void CopyTo(MemberInfo[] array, int startIndex) private int UnfilteredCount => ((_bindingAttr & BindingFlags.DeclaredOnly) != 0) ? _queriedMembers.DeclaredOnlyCount : _queriedMembers.TotalCount; + private readonly MemberPolicies _policies; private readonly BindingFlags _bindingAttr; private int _lazyCount; // Intentionally not marking as volatile. QueryResult is for short-term use within a single method call - no aspiration to be thread-safe. private QueriedMemberList _queriedMembers; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs index 8d68023a81653..27ad6e281d48a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs @@ -146,9 +146,8 @@ public static bool QualifiesBasedOnParameterCount(this MethodBase methodBase, Bi // - MethodImpls ignored. (I didn't say it made sense, this is just how the desktop api we're porting behaves.) // - Implemented interfaces ignores. (I didn't say it made sense, this is just how the desktop api we're porting behaves.) // - public static M GetImplicitlyOverriddenBaseClassMember(this M member) where M : MemberInfo + public static M GetImplicitlyOverriddenBaseClassMember(this M member, MemberPolicies policies) where M : MemberInfo { - MemberPolicies policies = MemberPolicies.Default; bool isVirtual; bool isNewSlot; policies.GetMemberAttributes(member, out _, out _, out isVirtual, out isNewSlot); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs index eebda9ca4a3b4..fb97779fa85ed 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs @@ -146,17 +146,17 @@ public sealed override FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFi public sealed override EventInfo GetImplicitlyOverriddenBaseClassEvent(EventInfo e) { - return e.GetImplicitlyOverriddenBaseClassMember(); + return e.GetImplicitlyOverriddenBaseClassMember(EventPolicies.Instance); } public sealed override MethodInfo GetImplicitlyOverriddenBaseClassMethod(MethodInfo m) { - return m.GetImplicitlyOverriddenBaseClassMember(); + return m.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance); } public sealed override PropertyInfo GetImplicitlyOverriddenBaseClassProperty(PropertyInfo p) { - return p.GetImplicitlyOverriddenBaseClassMember(); + return p.GetImplicitlyOverriddenBaseClassMember(PropertyPolicies.Instance); } private static FieldInfo GetFieldInfo(RuntimeTypeHandle declaringTypeHandle, FieldHandle fieldHandle) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index f9abaeae4f5bb..1bacedb637df7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -118,7 +118,7 @@ public sealed override MethodInfo GetBaseDefinition() while (true) { - MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember(); + MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance); if (next == null) return ((RuntimeMethodInfo)method).WithReflectedTypeSetToDeclaringType; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs index 562d2b3597c31..dcb0ed3e09332 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs @@ -11,14 +11,14 @@ namespace System.Reflection.Runtime.TypeInfos internal abstract partial class RuntimeTypeInfo { [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - public sealed override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => Query(bindingAttr).ToArray(); + public sealed override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => Query(ConstructorPolicies.Instance, bindingAttr).ToArray(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] protected sealed override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { Debug.Assert(types != null); - QueryResult queryResult = Query(bindingAttr); + QueryResult queryResult = Query(ConstructorPolicies.Instance, bindingAttr); ListBuilder candidates = new ListBuilder(); foreach (ConstructorInfo candidate in queryResult) { @@ -47,19 +47,19 @@ protected sealed override ConstructorInfo GetConstructorImpl(BindingFlags bindin } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] - public sealed override EventInfo[] GetEvents(BindingFlags bindingAttr) => Query(bindingAttr).ToArray(); + public sealed override EventInfo[] GetEvents(BindingFlags bindingAttr) => Query(EventPolicies.Instance, bindingAttr).ToArray(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] - public sealed override EventInfo GetEvent(string name, BindingFlags bindingAttr) => Query(name, bindingAttr).Disambiguate(); + public sealed override EventInfo GetEvent(string name, BindingFlags bindingAttr) => Query(EventPolicies.Instance, name, bindingAttr).Disambiguate(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] - public sealed override FieldInfo[] GetFields(BindingFlags bindingAttr) => Query(bindingAttr).ToArray(); + public sealed override FieldInfo[] GetFields(BindingFlags bindingAttr) => Query(FieldPolicies.Instance, bindingAttr).ToArray(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] - public sealed override FieldInfo GetField(string name, BindingFlags bindingAttr) => Query(name, bindingAttr).Disambiguate(); + public sealed override FieldInfo GetField(string name, BindingFlags bindingAttr) => Query(FieldPolicies.Instance, name, bindingAttr).Disambiguate(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] - public sealed override MethodInfo[] GetMethods(BindingFlags bindingAttr) => Query(bindingAttr).ToArray(); + public sealed override MethodInfo[] GetMethods(BindingFlags bindingAttr) => Query(MethodPolicies.Instance, bindingAttr).ToArray(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] protected sealed override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) @@ -85,12 +85,12 @@ private MethodInfo GetMethodImplCommon(string name, int genericParameterCount, B Debug.Assert(binder == null); Debug.Assert(callConvention == CallingConventions.Any); Debug.Assert(modifiers == null); - return Query(name, bindingAttr).Disambiguate(); + return Query(MethodPolicies.Instance, name, bindingAttr).Disambiguate(); } else { // Group #2: This group of api takes a set of parameter types and an optional binder. - QueryResult queryResult = Query(name, bindingAttr); + QueryResult queryResult = Query(MethodPolicies.Instance, name, bindingAttr); ListBuilder candidates = new ListBuilder(); foreach (MethodInfo candidate in queryResult) { @@ -114,13 +114,13 @@ private MethodInfo GetMethodImplCommon(string name, int genericParameterCount, B } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] - public sealed override Type[] GetNestedTypes(BindingFlags bindingAttr) => Query(bindingAttr).ToArray(); + public sealed override Type[] GetNestedTypes(BindingFlags bindingAttr) => Query(NestedTypePolicies.Instance, bindingAttr).ToArray(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] - public sealed override Type GetNestedType(string name, BindingFlags bindingAttr) => Query(name, bindingAttr).Disambiguate(); + public sealed override Type GetNestedType(string name, BindingFlags bindingAttr) => Query(NestedTypePolicies.Instance, name, bindingAttr).Disambiguate(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] - public sealed override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => Query(bindingAttr).ToArray(); + public sealed override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => Query(PropertyPolicies.Instance, bindingAttr).ToArray(); [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] protected sealed override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) @@ -133,12 +133,12 @@ protected sealed override PropertyInfo GetPropertyImpl(string name, BindingFlags // Group #1: This group of api accept only a name and BindingFlags. The other parameters are hard-wired by the non-virtual api entrypoints. Debug.Assert(binder == null); Debug.Assert(modifiers == null); - return Query(name, bindingAttr).Disambiguate(); + return Query(PropertyPolicies.Instance, name, bindingAttr).Disambiguate(); } else { // Group #2: This group of api takes a set of parameter types, a return type (both cannot be null) and an optional binder. - QueryResult queryResult = Query(name, bindingAttr); + QueryResult queryResult = Query(PropertyPolicies.Instance, name, bindingAttr); ListBuilder candidates = new ListBuilder(); foreach (PropertyInfo candidate in queryResult) { @@ -179,33 +179,32 @@ protected sealed override PropertyInfo GetPropertyImpl(string name, BindingFlags } } - private QueryResult Query(BindingFlags bindingAttr) where M : MemberInfo + private QueryResult Query(MemberPolicies policies, BindingFlags bindingAttr) where M : MemberInfo { - return Query(null, bindingAttr, null); + return Query(policies, null, bindingAttr, null); } - private QueryResult Query(string name, BindingFlags bindingAttr) where M : MemberInfo + private QueryResult Query(MemberPolicies policies, string name, BindingFlags bindingAttr) where M : MemberInfo { ArgumentNullException.ThrowIfNull(name); - return Query(name, bindingAttr, null); + return Query(policies, name, bindingAttr, null); } - private QueryResult Query(string optionalName, BindingFlags bindingAttr, Func optionalPredicate) where M : MemberInfo + private QueryResult Query(MemberPolicies policies, string optionalName, BindingFlags bindingAttr, Func optionalPredicate) where M : MemberInfo { - MemberPolicies policies = MemberPolicies.Default; bindingAttr = policies.ModifyBindingFlags(bindingAttr); bool ignoreCase = (bindingAttr & BindingFlags.IgnoreCase) != 0; TypeComponentsCache cache = Cache; QueriedMemberList queriedMembers; if (optionalName == null) - queriedMembers = cache.GetQueriedMembers(); + queriedMembers = cache.GetQueriedMembers(policies); else - queriedMembers = cache.GetQueriedMembers(optionalName, ignoreCase: ignoreCase); + queriedMembers = cache.GetQueriedMembers(policies, optionalName, ignoreCase: ignoreCase); if (optionalPredicate != null) queriedMembers = queriedMembers.Filter(optionalPredicate); - return new QueryResult(bindingAttr, queriedMembers); + return new QueryResult(policies, bindingAttr, queriedMembers); } private TypeComponentsCache Cache => _lazyCache ??= new TypeComponentsCache(this); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs index d992e97398cff..d0c82928f1928 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs @@ -51,21 +51,21 @@ private MemberInfo[] GetMemberImpl(string optionalNameOrPrefix, MemberTypes type MemberInfo[] results; - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.Method, out methods)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(MethodPolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.Method, out methods)) != null) return results; - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.Constructor, out constructors)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(ConstructorPolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.Constructor, out constructors)) != null) return results; - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.Property, out properties)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(PropertyPolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.Property, out properties)) != null) return results; - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.Event, out events)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(EventPolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.Event, out events)) != null) return results; - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.Field, out fields)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(FieldPolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.Field, out fields)) != null) return results; - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.NestedType, out nestedTypes)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(NestedTypePolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.NestedType, out nestedTypes)) != null) return results; if ((type & (MemberTypes.NestedType | MemberTypes.TypeInfo)) == MemberTypes.TypeInfo) { - if ((results = QuerySpecificMemberTypeIfRequested(type, optionalName, bindingAttr, predicate, MemberTypes.TypeInfo, out nestedTypes)) != null) + if ((results = QuerySpecificMemberTypeIfRequested(NestedTypePolicies.Instance, type, optionalName, bindingAttr, predicate, MemberTypes.TypeInfo, out nestedTypes)) != null) return results; } @@ -96,7 +96,7 @@ private MemberInfo[] GetMemberImpl(string optionalNameOrPrefix, MemberTypes type return results; } - private M[] QuerySpecificMemberTypeIfRequested(MemberTypes memberType, string optionalName, BindingFlags bindingAttr, Func optionalPredicate, MemberTypes targetMemberType, out QueryResult queryResult) where M : MemberInfo + private M[] QuerySpecificMemberTypeIfRequested(MemberPolicies policies, MemberTypes memberType, string optionalName, BindingFlags bindingAttr, Func optionalPredicate, MemberTypes targetMemberType, out QueryResult queryResult) where M : MemberInfo { if ((memberType & targetMemberType) == 0) { @@ -105,7 +105,7 @@ private M[] QuerySpecificMemberTypeIfRequested(MemberTypes memberType, string return null; } - queryResult = Query(optionalName, bindingAttr, optionalPredicate); + queryResult = Query(policies, optionalName, bindingAttr, optionalPredicate); // Desktop compat: If exactly one type of member was requested, the returned array has to be of that specific type (M[], not MemberInfo[]). Create it now and return it // to cause GetMember() to short-cut the search. @@ -137,19 +137,19 @@ private MemberInfo GetDeclaredMemberWithSameMetadataDefinitionAs(MemberInfo memb { return member.MemberType switch { - MemberTypes.Method => QueryMemberWithSameMetadataDefinitionAs(member), - MemberTypes.Constructor => QueryMemberWithSameMetadataDefinitionAs(member), - MemberTypes.Property => QueryMemberWithSameMetadataDefinitionAs(member), - MemberTypes.Field => QueryMemberWithSameMetadataDefinitionAs(member), - MemberTypes.Event => QueryMemberWithSameMetadataDefinitionAs(member), - MemberTypes.NestedType => QueryMemberWithSameMetadataDefinitionAs(member), + MemberTypes.Method => QueryMemberWithSameMetadataDefinitionAs(MethodPolicies.Instance, member), + MemberTypes.Constructor => QueryMemberWithSameMetadataDefinitionAs(ConstructorPolicies.Instance, member), + MemberTypes.Property => QueryMemberWithSameMetadataDefinitionAs(PropertyPolicies.Instance, member), + MemberTypes.Field => QueryMemberWithSameMetadataDefinitionAs(FieldPolicies.Instance, member), + MemberTypes.Event => QueryMemberWithSameMetadataDefinitionAs(EventPolicies.Instance, member), + MemberTypes.NestedType => QueryMemberWithSameMetadataDefinitionAs(NestedTypePolicies.Instance, member), _ => null, }; } - private M QueryMemberWithSameMetadataDefinitionAs(MemberInfo member) where M : MemberInfo + private M QueryMemberWithSameMetadataDefinitionAs(MemberPolicies policies, MemberInfo member) where M : MemberInfo { - QueryResult members = Query(member.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + QueryResult members = Query(policies, member.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); foreach (M candidate in members) { if (candidate.HasSameMetadataDefinitionAs(member)) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs index eb38835e487e5..3e70a4ac82143 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Collections.Generic; using System.Collections.Concurrent; using System.Reflection; @@ -43,12 +44,16 @@ public TypeComponentsCache(RuntimeTypeInfo type) // // BindingFlags == Public | NonPublic | Instance | Static | FlattenHierarchy // - public QueriedMemberList GetQueriedMembers(string name, bool ignoreCase) where M : MemberInfo + public QueriedMemberList GetQueriedMembers(MemberPolicies policies, string name, bool ignoreCase) where M : MemberInfo { - int index = MemberPolicies.MemberTypeIndex; + int index = policies.Index; object obj = ignoreCase ? _perNameQueryCaches_CaseInsensitive[index] : _perNameQueryCaches_CaseSensitive[index]; Debug.Assert(obj is PerNameQueryCache); PerNameQueryCache unifier = Unsafe.As>(obj); + + // Set the policies if they're not set yet. See the comment on SetPolicies on why we do this for details. + unifier.SetPolicies(policies); + QueriedMemberList result = unifier.GetOrAdd(name); return result; } @@ -58,13 +63,13 @@ public QueriedMemberList GetQueriedMembers(string name, bool ignoreCase) w // // BindingFlags == Public | NonPublic | Instance | Static | FlattenHierarchy // - public QueriedMemberList GetQueriedMembers() where M : MemberInfo + public QueriedMemberList GetQueriedMembers(MemberPolicies policies) where M : MemberInfo { - int index = MemberPolicies.MemberTypeIndex; + int index = policies.Index; object result = Volatile.Read(ref _nameAgnosticQueryCaches[index]); if (result == null) { - QueriedMemberList newResult = QueriedMemberList.Create(_type, optionalNameFilter: null, ignoreCase: false); + QueriedMemberList newResult = QueriedMemberList.Create(policies, _type, optionalNameFilter: null, ignoreCase: false); newResult.Compact(); result = newResult; Volatile.Write(ref _nameAgnosticQueryCaches[index], result); @@ -118,13 +123,23 @@ public PerNameQueryCache(RuntimeTypeInfo type, bool ignoreCase) _ignoreCase = ignoreCase; } + // This looks like something that should have been a parameter to the constructor, but we do this on + // purpose - the PerNameQueryCache instances are created eagerly, but not all apps might require + // MemberPolicies for all members. This allows us to delay creating the MemberPolicies instance + // until the need arises. + public void SetPolicies(MemberPolicies policies) + { + _policies = policies; + } + protected sealed override QueriedMemberList Factory(string key) { - QueriedMemberList result = QueriedMemberList.Create(_type, key, ignoreCase: _ignoreCase); + QueriedMemberList result = QueriedMemberList.Create(_policies, _type, key, ignoreCase: _ignoreCase); result.Compact(); return result; } + private MemberPolicies _policies; private readonly RuntimeTypeInfo _type; private readonly bool _ignoreCase; }