Skip to content

Accept Nullable element types in the ordered containers without a comparer - #77

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/containers-71-nullable-comparable
Sep 26, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/containers-71-nullable-comparable

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #71

When no comparer is passed, the constructors of OrderedSet<T>, OrderedCollection<T> and OrderedMap<TKey,TValue> required the type itself to implement IComparable<T> or IComparable. Nullable<U> implements neither, so new OrderedSet<int?>() threw ArgumentException, even though Comparer<int?>.Default orders nullable values with null first.

Change

  • Added an internal helper, Comparability.HasDefaultOrdering<T>(). It keeps the old check, and when the type is Nullable<U> it falls back to checking U.
  • Replaced all eight copies of the old check with the helper. That covers every no-comparer constructor of the three containers, including OrderedMap's primary-constructor field initializer.
  • A nullable wrapper around a type that is not comparable, such as KeyValuePair<int,int>?, is still rejected.

OrderedMap keeps its where TKey : notnull constraint, the same one Dictionary has. OrderedMap<int?, …> therefore still produces compiler warning CS8714, and null keys are still rejected at run time. The difference is that construction and ordering no longer fail.

Tests

  • For all three containers there are new tests that construct int? instances through the parameterless, capacity and collection constructors and check that the order matches Comparer<int?>.Default, with null first for the set and the collection.
  • There are also guard tests that the KeyValuePair<int,int>? case still throws.
  • I reverted the source changes and ran the tests again: the three construction tests fail. With the change they pass.
  • The full Containers.Test suite passes (395/395), and the Release build has no warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YXTjHR3MfJpmxt8LEwNkjm


Generated by Claude Code

…a comparer [patch]

The no-comparer constructors of OrderedSet, OrderedCollection and
OrderedMap required T itself to implement IComparable<T> or IComparable.
Nullable<U> implements neither, so int?, DateTime? and the like were
rejected even though Comparer<T>.Default orders them, null first.

Move the check into one Comparability.HasDefaultOrdering<T>() helper
that falls back to the nullable's underlying type, and use it in every
constructor of the three containers.

Fixes #71

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXTjHR3MfJpmxt8LEwNkjm
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 118606a into main Sep 26, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the claude/containers-71-nullable-comparable branch September 26, 2026 23:49
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.

OrderedSet/OrderedCollection/OrderedMap throw ArgumentException for Nullable<T> element types (int?, DateTime?) that Comparer<T>.Default supports

2 participants