Contributes to #80165.
Dispensing of reflection member infos is done through a member policies class. This is a generic class that has specialized implementations for each kind of member info.
It used a clever trick to get to the specific implementations. Just access `MemberPolicies<EventInfo>.Default` to get one for events or `MemberPolicies<PropertyInfo>.Default` to get one for properties. It was also absolutely not trimming friendly.
This change removes the clever trick and replaces it with good old fashioned parameter passing.
//==========================================================================================================================
internal sealed class ConstructorPolicies : MemberPolicies<ConstructorInfo>
{
+ public static readonly ConstructorPolicies Instance = new ConstructorPolicies();
+
+ public ConstructorPolicies() : base(MemberTypeIndex.Constructor) { }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<ConstructorInfo> GetDeclaredMembers(TypeInfo typeInfo)
//==========================================================================================================================
internal sealed class EventPolicies : MemberPolicies<EventInfo>
{
+ public static readonly EventPolicies Instance = new EventPolicies();
+
+ public EventPolicies() : base(MemberTypeIndex.Event) { }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<EventInfo> GetDeclaredMembers(TypeInfo typeInfo)
{
MethodInfo? baseAccessor = GetAccessorMethod(baseMember!);
MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!);
- return MemberPolicies<MethodInfo>.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor);
+ return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor);
}
public sealed override bool OkToIgnoreAmbiguity(EventInfo m1, EventInfo m2)
//==========================================================================================================================
internal sealed class FieldPolicies : MemberPolicies<FieldInfo>
{
+ public static readonly FieldPolicies Instance = new FieldPolicies();
+
+ public FieldPolicies() : base(MemberTypeIndex.Field) { }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<FieldInfo> GetDeclaredMembers(TypeInfo typeInfo)
//=================================================================================================================
internal abstract class MemberPolicies<M> where M : MemberInfo
{
+ public MemberPolicies(int index)
+ {
+ Index = index;
+ }
+
//=================================================================================================================
// Subclasses for specific MemberInfo types must override these:
//=================================================================================================================
return false;
}
- static MemberPolicies()
- {
- Type t = typeof(M);
- if (t.Equals(typeof(FieldInfo)))
- {
- MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Field;
- Default = (MemberPolicies<M>)(object)(new FieldPolicies());
- }
- else if (t.Equals(typeof(MethodInfo)))
- {
- MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Method;
- Default = (MemberPolicies<M>)(object)(new MethodPolicies());
- }
- else if (t.Equals(typeof(ConstructorInfo)))
- {
- MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Constructor;
- Default = (MemberPolicies<M>)(object)(new ConstructorPolicies());
- }
- else if (t.Equals(typeof(PropertyInfo)))
- {
- MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Property; ;
- Default = (MemberPolicies<M>)(object)(new PropertyPolicies());
- }
- else if (t.Equals(typeof(EventInfo)))
- {
- MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Event;
- Default = (MemberPolicies<M>)(object)(new EventPolicies());
- }
- else if (t.Equals(typeof(Type)))
- {
- MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.NestedType;
- Default = (MemberPolicies<M>)(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<M> 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; }
}
}
//==========================================================================================================================
internal sealed class MethodPolicies : MemberPolicies<MethodInfo>
{
+ public static readonly MethodPolicies Instance = new MethodPolicies();
+
+ public MethodPolicies() : base(MemberTypeIndex.Method) { }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<MethodInfo> GetDeclaredMembers(TypeInfo typeInfo)
//==========================================================================================================================
internal sealed class NestedTypePolicies : MemberPolicies<Type>
{
+ public static readonly NestedTypePolicies Instance = new NestedTypePolicies();
+
+ public NestedTypePolicies() : base(MemberTypeIndex.NestedType) { }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<Type> GetDeclaredMembers(TypeInfo typeInfo)
//==========================================================================================================================
internal sealed class PropertyPolicies : MemberPolicies<PropertyInfo>
{
+ public static readonly PropertyPolicies Instance = new PropertyPolicies();
+
+ public PropertyPolicies() : base(MemberTypeIndex.Property) { }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<PropertyInfo> GetDeclaredMembers(TypeInfo typeInfo)
{
MethodInfo? baseAccessor = GetAccessorMethod(baseMember!);
MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!);
- return MemberPolicies<MethodInfo>.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor);
+ return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor);
}
//
//
// Filter by name and visibility from the ReflectedType.
//
- public static QueriedMemberList<M> Create(RuntimeTypeInfo type, string optionalNameFilter, bool ignoreCase)
+ public static QueriedMemberList<M> Create(MemberPolicies<M> policies, RuntimeTypeInfo type, string optionalNameFilter, bool ignoreCase)
{
RuntimeTypeInfo reflectedType = type;
- MemberPolicies<M> policies = MemberPolicies<M>.Default;
-
NameFilter? nameFilter;
if (optionalNameFilter == null)
nameFilter = null;
//
internal partial struct QueryResult<M> where M : MemberInfo
{
- public QueryResult(BindingFlags bindingAttr, QueriedMemberList<M> queriedMembers)
+ public QueryResult(MemberPolicies<M> policies, BindingFlags bindingAttr, QueriedMemberList<M> queriedMembers)
{
+ _policies = policies;
_lazyCount = 0;
_bindingAttr = bindingAttr;
_queriedMembers = queriedMembers;
if (match.DeclaringType.Equals(challenger.DeclaringType))
throw new AmbiguousMatchException();
- MemberPolicies<M> policies = MemberPolicies<M>.Default;
- if (!policies.OkToIgnoreAmbiguity(match, challenger))
+ if (!_policies.OkToIgnoreAmbiguity(match, challenger))
throw new AmbiguousMatchException();
}
else
private int UnfilteredCount => ((_bindingAttr & BindingFlags.DeclaredOnly) != 0) ? _queriedMembers.DeclaredOnlyCount : _queriedMembers.TotalCount;
+ private readonly MemberPolicies<M> _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<M> _queriedMembers;
// - 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<M>(this M member) where M : MemberInfo
+ public static M GetImplicitlyOverriddenBaseClassMember<M>(this M member, MemberPolicies<M> policies) where M : MemberInfo
{
- MemberPolicies<M> policies = MemberPolicies<M>.Default;
bool isVirtual;
bool isNewSlot;
policies.GetMemberAttributes(member, out _, out _, out isVirtual, out isNewSlot);
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)
while (true)
{
- MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember();
+ MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance);
if (next == null)
return ((RuntimeMethodInfo)method).WithReflectedTypeSetToDeclaringType;
internal abstract partial class RuntimeTypeInfo
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
- public sealed override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => Query<ConstructorInfo>(bindingAttr).ToArray();
+ public sealed override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => Query<ConstructorInfo>(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<ConstructorInfo> queryResult = Query<ConstructorInfo>(bindingAttr);
+ QueryResult<ConstructorInfo> queryResult = Query<ConstructorInfo>(ConstructorPolicies.Instance, bindingAttr);
ListBuilder<ConstructorInfo> candidates = new ListBuilder<ConstructorInfo>();
foreach (ConstructorInfo candidate in queryResult)
{
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
- public sealed override EventInfo[] GetEvents(BindingFlags bindingAttr) => Query<EventInfo>(bindingAttr).ToArray();
+ public sealed override EventInfo[] GetEvents(BindingFlags bindingAttr) => Query<EventInfo>(EventPolicies.Instance, bindingAttr).ToArray();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
- public sealed override EventInfo GetEvent(string name, BindingFlags bindingAttr) => Query<EventInfo>(name, bindingAttr).Disambiguate();
+ public sealed override EventInfo GetEvent(string name, BindingFlags bindingAttr) => Query<EventInfo>(EventPolicies.Instance, name, bindingAttr).Disambiguate();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
- public sealed override FieldInfo[] GetFields(BindingFlags bindingAttr) => Query<FieldInfo>(bindingAttr).ToArray();
+ public sealed override FieldInfo[] GetFields(BindingFlags bindingAttr) => Query<FieldInfo>(FieldPolicies.Instance, bindingAttr).ToArray();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
- public sealed override FieldInfo GetField(string name, BindingFlags bindingAttr) => Query<FieldInfo>(name, bindingAttr).Disambiguate();
+ public sealed override FieldInfo GetField(string name, BindingFlags bindingAttr) => Query<FieldInfo>(FieldPolicies.Instance, name, bindingAttr).Disambiguate();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
- public sealed override MethodInfo[] GetMethods(BindingFlags bindingAttr) => Query<MethodInfo>(bindingAttr).ToArray();
+ public sealed override MethodInfo[] GetMethods(BindingFlags bindingAttr) => Query<MethodInfo>(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)
Debug.Assert(binder == null);
Debug.Assert(callConvention == CallingConventions.Any);
Debug.Assert(modifiers == null);
- return Query<MethodInfo>(name, bindingAttr).Disambiguate();
+ return Query<MethodInfo>(MethodPolicies.Instance, name, bindingAttr).Disambiguate();
}
else
{
// Group #2: This group of api takes a set of parameter types and an optional binder.
- QueryResult<MethodInfo> queryResult = Query<MethodInfo>(name, bindingAttr);
+ QueryResult<MethodInfo> queryResult = Query<MethodInfo>(MethodPolicies.Instance, name, bindingAttr);
ListBuilder<MethodInfo> candidates = new ListBuilder<MethodInfo>();
foreach (MethodInfo candidate in queryResult)
{
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
- public sealed override Type[] GetNestedTypes(BindingFlags bindingAttr) => Query<Type>(bindingAttr).ToArray();
+ public sealed override Type[] GetNestedTypes(BindingFlags bindingAttr) => Query<Type>(NestedTypePolicies.Instance, bindingAttr).ToArray();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
- public sealed override Type GetNestedType(string name, BindingFlags bindingAttr) => Query<Type>(name, bindingAttr).Disambiguate();
+ public sealed override Type GetNestedType(string name, BindingFlags bindingAttr) => Query<Type>(NestedTypePolicies.Instance, name, bindingAttr).Disambiguate();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
- public sealed override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => Query<PropertyInfo>(bindingAttr).ToArray();
+ public sealed override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => Query<PropertyInfo>(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)
// 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<PropertyInfo>(name, bindingAttr).Disambiguate();
+ return Query<PropertyInfo>(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<PropertyInfo> queryResult = Query<PropertyInfo>(name, bindingAttr);
+ QueryResult<PropertyInfo> queryResult = Query<PropertyInfo>(PropertyPolicies.Instance, name, bindingAttr);
ListBuilder<PropertyInfo> candidates = new ListBuilder<PropertyInfo>();
foreach (PropertyInfo candidate in queryResult)
{
}
}
- private QueryResult<M> Query<M>(BindingFlags bindingAttr) where M : MemberInfo
+ private QueryResult<M> Query<M>(MemberPolicies<M> policies, BindingFlags bindingAttr) where M : MemberInfo
{
- return Query<M>(null, bindingAttr, null);
+ return Query<M>(policies, null, bindingAttr, null);
}
- private QueryResult<M> Query<M>(string name, BindingFlags bindingAttr) where M : MemberInfo
+ private QueryResult<M> Query<M>(MemberPolicies<M> policies, string name, BindingFlags bindingAttr) where M : MemberInfo
{
ArgumentNullException.ThrowIfNull(name);
- return Query<M>(name, bindingAttr, null);
+ return Query<M>(policies, name, bindingAttr, null);
}
- private QueryResult<M> Query<M>(string optionalName, BindingFlags bindingAttr, Func<M, bool> optionalPredicate) where M : MemberInfo
+ private QueryResult<M> Query<M>(MemberPolicies<M> policies, string optionalName, BindingFlags bindingAttr, Func<M, bool> optionalPredicate) where M : MemberInfo
{
- MemberPolicies<M> policies = MemberPolicies<M>.Default;
bindingAttr = policies.ModifyBindingFlags(bindingAttr);
bool ignoreCase = (bindingAttr & BindingFlags.IgnoreCase) != 0;
TypeComponentsCache cache = Cache;
QueriedMemberList<M> queriedMembers;
if (optionalName == null)
- queriedMembers = cache.GetQueriedMembers<M>();
+ queriedMembers = cache.GetQueriedMembers(policies);
else
- queriedMembers = cache.GetQueriedMembers<M>(optionalName, ignoreCase: ignoreCase);
+ queriedMembers = cache.GetQueriedMembers<M>(policies, optionalName, ignoreCase: ignoreCase);
if (optionalPredicate != null)
queriedMembers = queriedMembers.Filter(optionalPredicate);
- return new QueryResult<M>(bindingAttr, queriedMembers);
+ return new QueryResult<M>(policies, bindingAttr, queriedMembers);
}
private TypeComponentsCache Cache => _lazyCache ??= new TypeComponentsCache(this);
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;
}
return results;
}
- private M[] QuerySpecificMemberTypeIfRequested<M>(MemberTypes memberType, string optionalName, BindingFlags bindingAttr, Func<MemberInfo, bool> optionalPredicate, MemberTypes targetMemberType, out QueryResult<M> queryResult) where M : MemberInfo
+ private M[] QuerySpecificMemberTypeIfRequested<M>(MemberPolicies<M> policies, MemberTypes memberType, string optionalName, BindingFlags bindingAttr, Func<MemberInfo, bool> optionalPredicate, MemberTypes targetMemberType, out QueryResult<M> queryResult) where M : MemberInfo
{
if ((memberType & targetMemberType) == 0)
{
return null;
}
- queryResult = Query<M>(optionalName, bindingAttr, optionalPredicate);
+ queryResult = Query<M>(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.
{
return member.MemberType switch
{
- MemberTypes.Method => QueryMemberWithSameMetadataDefinitionAs<MethodInfo>(member),
- MemberTypes.Constructor => QueryMemberWithSameMetadataDefinitionAs<ConstructorInfo>(member),
- MemberTypes.Property => QueryMemberWithSameMetadataDefinitionAs<PropertyInfo>(member),
- MemberTypes.Field => QueryMemberWithSameMetadataDefinitionAs<FieldInfo>(member),
- MemberTypes.Event => QueryMemberWithSameMetadataDefinitionAs<EventInfo>(member),
- MemberTypes.NestedType => QueryMemberWithSameMetadataDefinitionAs<Type>(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<M>(MemberInfo member) where M : MemberInfo
+ private M QueryMemberWithSameMetadataDefinitionAs<M>(MemberPolicies<M> policies, MemberInfo member) where M : MemberInfo
{
- QueryResult<M> members = Query<M>(member.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ QueryResult<M> members = Query<M>(policies, member.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
foreach (M candidate in members)
{
if (candidate.HasSameMetadataDefinitionAs(member))
using System.Threading;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection;
//
// BindingFlags == Public | NonPublic | Instance | Static | FlattenHierarchy
//
- public QueriedMemberList<M> GetQueriedMembers<M>(string name, bool ignoreCase) where M : MemberInfo
+ public QueriedMemberList<M> GetQueriedMembers<M>(MemberPolicies<M> policies, string name, bool ignoreCase) where M : MemberInfo
{
- int index = MemberPolicies<M>.MemberTypeIndex;
+ int index = policies.Index;
object obj = ignoreCase ? _perNameQueryCaches_CaseInsensitive[index] : _perNameQueryCaches_CaseSensitive[index];
Debug.Assert(obj is PerNameQueryCache<M>);
PerNameQueryCache<M> unifier = Unsafe.As<PerNameQueryCache<M>>(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<M> result = unifier.GetOrAdd(name);
return result;
}
//
// BindingFlags == Public | NonPublic | Instance | Static | FlattenHierarchy
//
- public QueriedMemberList<M> GetQueriedMembers<M>() where M : MemberInfo
+ public QueriedMemberList<M> GetQueriedMembers<M>(MemberPolicies<M> policies) where M : MemberInfo
{
- int index = MemberPolicies<M>.MemberTypeIndex;
+ int index = policies.Index;
object result = Volatile.Read(ref _nameAgnosticQueryCaches[index]);
if (result == null)
{
- QueriedMemberList<M> newResult = QueriedMemberList<M>.Create(_type, optionalNameFilter: null, ignoreCase: false);
+ QueriedMemberList<M> newResult = QueriedMemberList<M>.Create(policies, _type, optionalNameFilter: null, ignoreCase: false);
newResult.Compact();
result = newResult;
Volatile.Write(ref _nameAgnosticQueryCaches[index], result);
_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<M> policies)
+ {
+ _policies = policies;
+ }
+
protected sealed override QueriedMemberList<M> Factory(string key)
{
- QueriedMemberList<M> result = QueriedMemberList<M>.Create(_type, key, ignoreCase: _ignoreCase);
+ QueriedMemberList<M> result = QueriedMemberList<M>.Create(_policies, _type, key, ignoreCase: _ignoreCase);
result.Compact();
return result;
}
+ private MemberPolicies<M> _policies;
private readonly RuntimeTypeInfo _type;
private readonly bool _ignoreCase;
}