Skip to content

Report a struct once when a collection repeats it - #91

Open
tgharold wants to merge 3 commits into
masterfrom
tgh-20261002-enumerate-collections-once
Open

tgharold wants to merge 3 commits into
masterfrom
tgh-20261002-enumerate-collections-once

Conversation

@tgharold

@tgharold tgharold commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Motivation

A struct has no identity, so the walk reported an invalid struct once for each route that reached it. The extra routes came from two sources. First, a collection that is an item or the root object had its framework properties walked, and those repeat the items: a LinkedList<Line> item reported one struct four times, through [0], First.Value, First.ValueRef and First.List[0]. Second, a collection that two routes reach was enumerated once per route. The same collection held in a property already reported once, so an item and a property behaved differently. This is a 3.0 decision ("fix both causes"), because it changes the result list.

Summary

  • For a collection, GetWalkedProperties leaves out the properties that System.* types declare, such as ArraySegment<T>.Array, LinkedList<T>.First and Dictionary<TKey, TValue>.Values. Properties that a user collection type adds, such as PagedList.Cursor, are still walked. IsLeafType uses the same method, so int[] and ArraySegment<int> become leaf types. The Array.SyncRoot special case in the walk is gone.
  • The walk remembers each collection it enumerated. A second route enumerates it again, so an item that a Validate method added in the meantime is still found, but skips its struct items. Class items were already dropped by reference. A first version enumerated each collection only once, and it broke An_item_that_adds_to_the_list_that_holds_it_does_not_make_enumeration_throw, so it was narrowed.
  • BREAKING: duplicate paths go away. An object that only a framework collection property reached is no longer validated: an array element outside an ArraySegment, or a dictionary's comparer. A jagged int[][] is no longer enumerated.
  • Known limit that stays: two properties that each return a struct, such as a computed copy, give two values and two results.
  • StructItemsReportedTwiceTests is now StructsReachedByTwoRoutesTests. README and changelog are updated.

Test plan

  • Specs first: 9 new specs fail against master, and the guards pass
  • With the fix: 617 passed, 7 skipped on net8.0 and net10.0
  • Test project builds for net481 with -p:IncludeNetFramework=true
  • CI passes, including net481 on Windows

tgharold and others added 3 commits October 2, 2026 18:00
A struct reached by two routes is to be reported once where the
validator can tell: a collection is enumerated once, and the
properties that framework types declare on an item or root collection
are not walked. Specs: a shared array, a list in a property and an
item (still validated as an object), an ArraySegment, LinkedList and
dictionary item, a root LinkedList, and an object outside an
ArraySegment, which is no longer reached.

Guards: a class object is reported once, a computed struct copy is
still reported twice, and Tuple and KeyValuePair keep their walked
properties.

Rename StructItemsReportedTwiceTests to StructsReachedByTwoRoutesTests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
For a collection that is an item or the root object, the properties
that framework types declare are no longer walked, as for a
collection that a property holds. They repeat the items:
ArraySegment.Array, LinkedList.First, Dictionary.Values. The rule
lives in GetWalkedProperties, so IsLeafType agrees: int[] and
ArraySegment<int> are now leaf types. The Array.SyncRoot special
case is no longer needed.

The walk remembers each collection it enumerated. A second route
enumerates it again, so an item that a Validate method added is
still found, but skips its struct items, which the first route
reported. Class items were already dropped by reference.

The spec for a list in a property and an item is renamed, because the
list is enumerated twice; only its struct is reported once.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
README: a struct in a shared collection is reported once, and the
properties that framework types declare on a collection item are not
walked. Only a computed copy of a struct is still reported twice.

Changelog: a BREAKING entry for the removed routes and the objects
that only those routes reached, and a narrower struct known limit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@tgharold tgharold mentioned this pull request Oct 2, 2026
3 of 4 tasks

This branch has not been deployed

No deployments
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.

1 participant