@@ -7,6 +7,10 @@ internal static class DynamicDataOperations
77{
88 private const BindingFlags DeclaredOnlyLookup = BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Static | BindingFlags . DeclaredOnly ;
99
10+ private static readonly ConcurrentDictionary < TypeMemberKey , FieldInfo ? > FieldCache = new ( ) ;
11+ private static readonly ConcurrentDictionary < TypeMemberKey , PropertyInfo ? > PropertyCache = new ( ) ;
12+ private static readonly ConcurrentDictionary < TypeMemberKey , MethodInfo ? > MethodCache = new ( ) ;
13+
1014 public static IEnumerable < object [ ] > GetData ( Type ? dynamicDataDeclaringType , DynamicDataSourceType dynamicDataSourceType , string dynamicDataSourceName , object ? [ ] dynamicDataSourceArguments , MethodInfo methodInfo )
1115 {
1216 // Check if the declaring type of test data is passed in. If not, default to test method's class type.
@@ -167,6 +171,15 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume
167171 }
168172
169173 private static FieldInfo ? GetFieldConsideringInheritance ( Type type , string fieldName )
174+ => FieldCache . GetOrAdd ( new TypeMemberKey ( type , fieldName ) , static key => LookupFieldInHierarchy ( key . Type , key . Name ) ) ;
175+
176+ private static PropertyInfo ? GetPropertyConsideringInheritance ( Type type , string propertyName )
177+ => PropertyCache . GetOrAdd ( new TypeMemberKey ( type , propertyName ) , static key => LookupPropertyInHierarchy ( key . Type , key . Name ) ) ;
178+
179+ private static MethodInfo ? GetMethodConsideringInheritance ( Type type , string methodName )
180+ => MethodCache . GetOrAdd ( new TypeMemberKey ( type , methodName ) , static key => LookupMethodInHierarchy ( key . Type , key . Name ) ) ;
181+
182+ private static FieldInfo ? LookupFieldInHierarchy ( Type type , string fieldName )
170183 {
171184 // NOTE: Don't use GetRuntimeField. It considers inheritance only for instance fields.
172185 Type ? currentType = type ;
@@ -184,7 +197,7 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume
184197 return null ;
185198 }
186199
187- private static PropertyInfo ? GetPropertyConsideringInheritance ( Type type , string propertyName )
200+ private static PropertyInfo ? LookupPropertyInHierarchy ( Type type , string propertyName )
188201 {
189202 // NOTE: Don't use GetRuntimeProperty. It considers inheritance only for instance properties.
190203 Type ? currentType = type ;
@@ -202,7 +215,7 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume
202215 return null ;
203216 }
204217
205- private static MethodInfo ? GetMethodConsideringInheritance ( Type type , string methodName )
218+ private static MethodInfo ? LookupMethodInHierarchy ( Type type , string methodName )
206219 {
207220 // NOTE: Don't use GetRuntimeMethod. It considers inheritance only for instance methods.
208221 Type ? currentType = type ;
@@ -219,4 +232,29 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume
219232
220233 return null ;
221234 }
235+
236+ private readonly struct TypeMemberKey : IEquatable < TypeMemberKey >
237+ {
238+ public TypeMemberKey ( Type type , string name )
239+ {
240+ Type = type ;
241+ Name = name ;
242+ }
243+
244+ public Type Type { get ; }
245+
246+ public string Name { get ; }
247+
248+ public bool Equals ( TypeMemberKey other ) => Type == other . Type && Name == other . Name ;
249+
250+ public override bool Equals ( object ? obj ) => obj is TypeMemberKey other && Equals ( other ) ;
251+
252+ public override int GetHashCode ( )
253+ {
254+ int h1 = Type . GetHashCode ( ) ;
255+ int h2 = StringComparer . Ordinal . GetHashCode ( Name ) ;
256+
257+ return ( ( h1 << 5 ) + h1 ) ^ h2 ;
258+ }
259+ }
222260}
0 commit comments