@@ -86,7 +86,7 @@ public partial class ODataConventionModelBuilder : ODataModelBuilder
8686 private bool _isQueryCompositionMode ;
8787
8888 // build the mapping between type and its derived types to be used later.
89- private Lazy < IDictionary < Type , List < Type > > > _allTypesWithDerivedTypeMapping ;
89+ private Lazy < IDictionary < Type , Type [ ] > > _allTypesWithDerivedTypeMapping ;
9090
9191 /// <summary>
9292 /// Initializes a new <see cref="ODataConventionModelBuilder"/>.
@@ -133,7 +133,7 @@ internal void Initialize(IWebApiAssembliesResolver assembliesResolver, bool isQu
133133 _mappedTypes = new HashSet < StructuralTypeConfiguration > ( ) ;
134134 _ignoredTypes = new HashSet < Type > ( ) ;
135135 ModelAliasingEnabled = true ;
136- _allTypesWithDerivedTypeMapping = new Lazy < IDictionary < Type , List < Type > > > (
136+ _allTypesWithDerivedTypeMapping = new Lazy < IDictionary < Type , Type [ ] > > (
137137 ( ) => BuildDerivedTypesMapping ( assembliesResolver ) ,
138138 isThreadSafe : false ) ;
139139 }
@@ -603,7 +603,7 @@ internal void MapDerivedTypes(StructuralTypeConfiguration structuralType)
603603 StructuralTypeConfiguration baseType = typeToBeVisited . Dequeue ( ) ;
604604 visitedTypes . Add ( baseType . ClrType ) ;
605605
606- List < Type > derivedTypes ;
606+ Type [ ] derivedTypes ;
607607 if ( _allTypesWithDerivedTypeMapping . Value . TryGetValue ( baseType . ClrType , out derivedTypes ) )
608608 {
609609 foreach ( Type derivedType in derivedTypes )
@@ -825,7 +825,7 @@ internal void ReconfigInferedEntityTypeAsComplexType(Type propertyType)
825825 Type currentType = typeToBeVisited . Dequeue ( ) ;
826826 visitedTypes . Add ( currentType ) ;
827827
828- List < Type > derivedTypes ;
828+ Type [ ] derivedTypes ;
829829 if ( _allTypesWithDerivedTypeMapping . Value . TryGetValue ( currentType , out derivedTypes ) )
830830 {
831831 foreach ( Type derivedType in derivedTypes )
@@ -865,7 +865,7 @@ internal bool InferEdmTypeFromDerivedTypes(Type propertyType, ref PropertyKind p
865865 Type currentType = typeToBeVisited . Dequeue ( ) ;
866866 visitedTypes . Add ( currentType ) ;
867867
868- List < Type > derivedTypes ;
868+ Type [ ] derivedTypes ;
869869 if ( _allTypesWithDerivedTypeMapping . Value . TryGetValue ( currentType , out derivedTypes ) )
870870 {
871871 foreach ( Type derivedType in derivedTypes )
@@ -1080,21 +1080,48 @@ private void ReapplyPropertyConvention(PropertyConfiguration property,
10801080 }
10811081 }
10821082
1083- private static Dictionary < Type , List < Type > > BuildDerivedTypesMapping ( IWebApiAssembliesResolver assemblyResolver )
1083+ private static Dictionary < Type , Type [ ] > BuildDerivedTypesMapping ( IWebApiAssembliesResolver assemblyResolver )
10841084 {
1085- IEnumerable < Type > allTypes = TypeHelper . GetLoadedTypes ( assemblyResolver ) . Where ( t => TypeHelper . IsVisible ( t ) && TypeHelper . IsClass ( t ) && t != typeof ( object ) ) ;
1086- Dictionary < Type , List < Type > > allTypeMapping = allTypes . Distinct ( ) . ToDictionary ( k => k , k => new List < Type > ( ) ) ;
1087-
1088- foreach ( Type type in allTypes )
1085+ Predicate < Type > verifyType = t => TypeHelper . IsVisible ( t ) && TypeHelper . IsClass ( t ) && t != typeof ( object ) ;
1086+
1087+ // The dictionary is allocated to contain all visible reference types which is not system.Object, each with an List<Type> allocated.
1088+ // The list is used to keep derived types.
1089+ // In a common scenario, there are about 10% types with derived types.
1090+ // So, we don't need to keep a large number of empty list in the dictionary.
1091+ Dictionary < Type , List < Type > > temp = new Dictionary < Type , List < Type > > ( ) ;
1092+ foreach ( Type type in TypeHelper . GetLoadedTypes ( assemblyResolver ) )
10891093 {
1090- List < Type > derivedTypes ;
1091- if ( TypeHelper . GetBaseType ( type ) != null && allTypeMapping . TryGetValue ( TypeHelper . GetBaseType ( type ) , out derivedTypes ) )
1094+ if ( type != null && verifyType ( type ) )
10921095 {
1093- derivedTypes . Add ( type ) ;
1096+ Type baseType = TypeHelper . GetBaseType ( type ) ;
1097+ if ( baseType != null )
1098+ {
1099+ List < Type > list ;
1100+ if ( ! temp . TryGetValue ( baseType , out list ) )
1101+ {
1102+ if ( verifyType ( baseType ) )
1103+ {
1104+ list = new List < Type > ( 1 ) ;
1105+ temp [ baseType ] = list ;
1106+ }
1107+ }
1108+
1109+ if ( list != null )
1110+ {
1111+ list . Add ( type ) ;
1112+ }
1113+ }
10941114 }
10951115 }
10961116
1097- return allTypeMapping ;
1117+ // We can throw away all lists and keep the dictionary as small as possible
1118+ Dictionary < Type , Type [ ] > map = new Dictionary < Type , Type [ ] > ( temp . Count ) ;
1119+ foreach ( var kv in temp )
1120+ {
1121+ map [ kv . Key ] = kv . Value . ToArray ( ) ;
1122+ }
1123+
1124+ return map ;
10981125 }
10991126
11001127 /// <inheritdoc />
0 commit comments