Skip to content

Simplify DynamicData reflection lookups using FlattenHierarchy#7535

Merged
Evangelink merged 4 commits intomainfrom
perf/cache-reflection-in-dynamic-data-operations
Apr 23, 2026
Merged

Simplify DynamicData reflection lookups using FlattenHierarchy#7535
Evangelink merged 4 commits intomainfrom
perf/cache-reflection-in-dynamic-data-operations

Conversation

@Evangelink
Copy link
Copy Markdown
Member

@Evangelink Evangelink commented Mar 12, 2026

Replace the manual DeclaredOnly + BaseType walk in DynamicDataOperations with direct reflection lookups using BindingFlags.FlattenHierarchy, and inline the helper methods at their call sites.

Behavior change: FlattenHierarchy does not return private static members from base types, while the previous loop-based approach did. This is accepted as a reasonable tradeoff — accessing private members of a base class via [DynamicData] is an unusual pattern.

The DynamicDataShouldBeValidAnalyzer has been updated to match: TryGetMemberCore now filters out private members when looking at base types.

Copilot AI review requested due to automatic review settings March 12, 2026 15:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves DynamicData reflection performance in MSTest’s DynamicDataOperations by caching inheritance-walking member lookups (fields/properties/methods) so repeated calls don’t traverse the full type hierarchy every time.

Changes:

  • Added per-member-kind ConcurrentDictionary caches keyed by (Type, memberName) (via a custom TypeMemberKey struct).
  • Refactored the existing hierarchy-walk implementations into Lookup*InHierarchy helpers and routed Get*ConsideringInheritance through the caches.

You can also share your feedback on Copilot code review. Take the survey.

Copy link
Copy Markdown
Member

@Youssef1313 Youssef1313 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Have we seen real perf issues here that warrants adding a cache?
  • I feel like walking the inheritance hierarchy is already not the right approach. Instead, we should avoid BindingFlags.DeclaredOnly and let the .NET runtime do its thing. The .NET reflection implementation has some caching already, so if we are able to avoid walking the hierarchy ourselves and let the caching behavior of reflection do its job, I think that's the best.

…l hierarchy walk

Replace the manual type hierarchy walk with DeclaredOnly + loop with a single reflection call using BindingFlags.FlattenHierarchy. This lets the .NET runtime handle inheritance search for static members with its own built-in caching, removing the need for custom ConcurrentDictionary caches and the TypeMemberKey struct.
@Evangelink
Copy link
Copy Markdown
Member Author

@Youssef1313 Great suggestion — replaced the manual hierarchy walk + caching with a single reflection call using BindingFlags.FlattenHierarchy instead of DeclaredOnly. This removes the ConcurrentDictionary caches, the TypeMemberKey struct, and the Lookup*InHierarchy helpers — net result is -49 lines, +4 lines. All 775 tests pass.

@Evangelink Evangelink force-pushed the perf/cache-reflection-in-dynamic-data-operations branch from 96f1ad1 to 28dac23 Compare March 12, 2026 15:54
@Evangelink Evangelink enabled auto-merge March 12, 2026 15:54
Comment thread src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataOperations.cs Outdated
Copy link
Copy Markdown
Member

@Youssef1313 Youssef1313 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with two small comments.

Copilot AI review requested due to automatic review settings March 12, 2026 20:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment thread src/TestFramework/TestFramework/Attributes/DataSource/DynamicDataOperations.cs Outdated
…to disallow private base members

- Remove trailing blank line in DynamicDataOperations.cs (Thread 5)
- Update DynamicDataShouldBeValidAnalyzer.TryGetMemberCore to filter out private
  members from base types, matching the FlattenHierarchy runtime behavior (Thread 4)
- Add test WhenPrivateMemberIsFromBase_Diagnostic to cover the new behavior
@Evangelink Evangelink changed the title Cache reflection lookups in DynamicDataOperations Simplify DynamicData reflection lookups using FlattenHierarchy Apr 23, 2026
@Evangelink Evangelink merged commit bb688dd into main Apr 23, 2026
10 checks passed
@Evangelink Evangelink deleted the perf/cache-reflection-in-dynamic-data-operations branch April 23, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants