Equivalency: fail when applying member-level selection to value-semantics (fixes #2571) #1
+76
−1
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This change enforces a clear failure when callers attempt to apply member/path-level selection rules (e.g.,
Excluding(...),Including(...)by path) to types that are compared using value semantics (i.e.,Equalsoverride or explicitComparingByValue/ForceEquals). Previously such rules could be silently ignored or produce inconsistent behavior across overloads.What I changed
Equivalency logic
Src/FluentAssertions/Equivalency/EquivalencyValidator.csExcludeMemberByPathSelectionRule) targets a node whose type is compared by value semantics, the assertion fails with an actionable message explaining how to resolve the issue (for example,ComparingByMembers<T>()). The check is conservative: it ignores primitive/value types andstring, and it only fails for non-primitive reference types which either overrideEqualsor are explicitly forced to useEquals.Tests
Tests/FluentAssertions.Equivalency.Specs/SelectionRulesSpecs.Excluding.csExcluding(...)on a type that overridesEqualsresults in a helpful failure instead of being silently ignored.Tests/FluentAssertions.Equivalency.Specs/TestTypes.csValueSemanticWithPropertyhelper type used in the spec.Rationale
Notes & limitations
This initial implementation enforces the rule for path-based selection rules (exclude-by-path). It does not yet enforce for predicate-based selection rules (
Excluding(ctx => ...)) because those can apply at arbitrary depths and require more nuanced runtime analysis to decide whether they definitely target a specific type/member. I can extend enforcement to include predicate-based rules in a follow-up change.The check ignores primitive types and
stringbecause excluding members that are primitive or strings is harmless and expected.I ran the full test suite locally. All test cases executed, and 18610 tests passed; a single build error was emitted by one legacy test target due to an outdated VSTest MSBuild target on .NET 10 (this is unrelated to the change).
How to review
EquivalencyValidator.csfor enforcement logic and the small test added to the existing specs.IncludeMemberByPathSelectionRuleand consider predicate-based rules.