1- // Copyright (C) 2008-2021 Xtensive LLC.
1+ // Copyright (C) 2008-2022 Xtensive LLC.
22// This code is distributed under MIT license terms.
33// See the License.txt file in the project root for more information.
44// Created by: Alex Yakunin
1111using System . Reflection ;
1212using AttributesKey = System . ValueTuple < System . Reflection . MemberInfo , System . Type , Xtensive . Reflection . AttributeSearchOptions > ;
1313using PerAttributeKey = System . ValueTuple < System . Reflection . MemberInfo , Xtensive . Reflection . AttributeSearchOptions > ;
14+ using Xtensive . Core ;
1415
1516namespace Xtensive . Reflection
1617{
@@ -71,7 +72,7 @@ public static TAttribute GetAttribute<TAttribute>(this MemberInfo member, Attrib
7172 private static IReadOnlyList < Attribute > GetAttributes ( MemberInfo member , Type attributeType , AttributeSearchOptions options ) =>
7273 attributesByMemberInfoAndSearchOptions . GetOrAdd (
7374 new AttributesKey ( member , attributeType , options ) ,
74- t => ExtractAttributes ( t ) . ToArray ( )
75+ t => ExtractAttributes ( t , out var count ) . ToArray ( count )
7576 ) ;
7677
7778 private static Attribute [ ] GetAttributes ( this MemberInfo member , Type attributeType )
@@ -84,30 +85,48 @@ private static Attribute[] GetAttributes(this MemberInfo member, Type attributeT
8485 return attrs ;
8586 }
8687
87- private static IEnumerable < Attribute > ExtractAttributes ( ( MemberInfo member , Type attributeType , AttributeSearchOptions options ) t ) {
88+ private static IEnumerable < Attribute > ExtractAttributes ( ( MemberInfo member , Type attributeType , AttributeSearchOptions options ) t , out int count )
89+ {
8890 ( var member , var attributeType , var options ) = t ;
8991
90- var attributes = member . GetCustomAttributes ( attributeType , false ) . Cast < Attribute > ( ) . ToList ( ) ;
91- if ( options == AttributeSearchOptions . InheritNone )
92- return attributes ;
93- if ( attributes . Count == 0 ) {
92+ var customAttributesRaw = member . GetCustomAttributes ( attributeType , false ) ;
93+ count = customAttributesRaw . Length ;
94+
95+ if ( options == AttributeSearchOptions . InheritNone ) {
96+ return ( customAttributesRaw . Length == 0 )
97+ ? Array . Empty < Attribute > ( )
98+ : customAttributesRaw . Cast < Attribute > ( ) ; // no new collection
99+ }
100+
101+ IEnumerable < Attribute > attributes ;
102+ if ( customAttributesRaw . Length == 0 ) {
103+ attributes = Enumerable . Empty < Attribute > ( ) ;
94104 if ( ( options & AttributeSearchOptions . InheritFromPropertyOrEvent ) != 0
95105 && member is MethodInfo m
96106 && ( ( MemberInfo ) m . GetProperty ( ) ?? m . GetEvent ( ) ) is MemberInfo poe ) {
97- attributes = poe . GetAttributes ( attributeType ) . ToList ( ) ;
107+ var poeAttributes = poe . GetAttributes ( attributeType ) ;
108+ count = poeAttributes . Length ;
109+ attributes = poeAttributes ;
98110 }
99111 if ( ( options & AttributeSearchOptions . InheritFromBase ) != 0
100112 && ( options & AttributeSearchOptions . InheritRecursively ) == 0
101113 && member . GetBaseMember ( ) is MemberInfo bm ) {
102- attributes . AddRange ( GetAttributes ( bm , attributeType , options ) ) ;
114+ var inheritedAttributes = GetAttributes ( bm , attributeType , options ) ;
115+ count += inheritedAttributes . Count ;
116+ attributes = attributes . Concat ( inheritedAttributes ) ;
103117 return attributes ;
104118 }
105119 }
120+ else {
121+ attributes = customAttributesRaw . Cast < Attribute > ( ) ;
122+ }
106123
107124 if ( ( options & AttributeSearchOptions . InheritFromAllBase ) == AttributeSearchOptions . InheritFromAllBase
108125 && member . DeclaringType != WellKnownTypes . Object
109126 && member . GetBaseMember ( ) is MemberInfo bm2 ) {
110- attributes . AddRange ( GetAttributes ( bm2 , attributeType , options ) ) ;
127+ var inheritedAttributes = GetAttributes ( bm2 , attributeType , options ) ;
128+ count += inheritedAttributes . Count ;
129+ attributes = attributes . Concat ( inheritedAttributes ) ;
111130 }
112131
113132 return attributes ;
0 commit comments