| File: System\Reflection\Runtime\BindingFlagSupport\QueryResult.cs | Web Access |
| Project: src\runtime\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; namespace System.Reflection.Runtime.BindingFlagSupport { // // Stores the result of a member filtering that's further filtered by the Public, NonPublic, Instance, Static and FlatternHierarchy bits of BindingFlags. // This object is not considered a candidate for long term caching. // // Note: The uninitialized state ("qr = default(QueryResult<M>)) is considered a valid state for this object, and represents an empty list of members. // internal partial struct QueryResult<M> where M : MemberInfo { public QueryResult(BindingFlags bindingAttr, QueriedMemberList<M> queriedMembers) { _lazyCount = 0; _bindingAttr = bindingAttr; _queriedMembers = queriedMembers; } public QueryResultEnumerator GetEnumerator() => new QueryResultEnumerator(this); /// <summary> /// Returns the number of matching results. /// </summary> public int Count { get { int count = _lazyCount; if (count == 0) { if (_queriedMembers == null) return 0; // This is an uninitialized QueryResult<M>, which is supported and represents a 0-length list of matches. int unfilteredCount = UnfilteredCount; for (int i = 0; i < unfilteredCount; i++) { if (_queriedMembers.Matches(i, _bindingAttr)) count++; } if (count == 0) { // If no matches were found, set ourselves back to the "uninitialized" state so that future // calls to Count won't go through this calculation again. _queriedMembers = null; } _lazyCount = count; } return count; } } /// <summary> /// Copies the results to a freshly allocated array. Use this at api boundary points. /// </summary> public M[] ToArray() { int count = Count; if (count == 0) return Array.Empty<M>(); M[] newArray = new M[count]; CopyTo(newArray, 0); return newArray; } /// <summary> /// Copies the results into an existing array. /// </summary> public void CopyTo(MemberInfo[] array, int startIndex) { if (_queriedMembers == null) return; // This is an uninitialized QueryResult<M>, which is supported and represents a 0-length list of matches. int unfilteredCount = UnfilteredCount; for (int i = 0; i < unfilteredCount; i++) { if (_queriedMembers.Matches(i, _bindingAttr)) { array[startIndex++] = _queriedMembers[i]; } } } /// <summary> /// Returns a single member, null or throws AmbiguousMatchException, for the Type.Get*(string name,...) family of apis. /// </summary> public M? Disambiguate() { if (_queriedMembers == null) return null; // This is an uninitialized QueryResult<M>, which is supported and represents a 0-length list of matches. int unfilteredCount = UnfilteredCount; M? match = null; for (int i = 0; i < unfilteredCount; i++) { if (_queriedMembers.Matches(i, _bindingAttr)) { if (match != null) { M challenger = _queriedMembers[i]; // Assuming the policy says it's ok to ignore the ambiguity, we're to resolve in favor of the member // declared by the most derived type. Since QueriedMemberLists are sorted in order of decreasing derivation, // that means we let the first match win - unless, of course, they're both the "most derived member". if (match.DeclaringType!.Equals(challenger.DeclaringType)) throw ThrowHelper.GetAmbiguousMatchException(match); MemberPolicies<M> policies = MemberPolicies<M>.Default; if (!policies.OkToIgnoreAmbiguity(match, challenger)) throw ThrowHelper.GetAmbiguousMatchException(match); } else { match = _queriedMembers[i]; } } } return match; } private int UnfilteredCount => ((_bindingAttr & BindingFlags.DeclaredOnly) != 0) ? _queriedMembers!.DeclaredOnlyCount : _queriedMembers!.TotalCount; 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; } }