Skip to content

Fix HashSet.TryGetValue throwing for null with a StringComparer - #628

Merged
SimonCropp merged 1 commit into
mainfrom
fix/hashset-trygetvalue
Oct 11, 2026
Merged

SimonCropp merged 1 commit into
mainfrom
fix/hashset-trygetvalue

Conversation

@SimonCropp

Copy link
Copy Markdown
Owner

Bug

The HashSet<T>.TryGetValue polyfill (active below net472) called comparer.GetHashCode on the lookup value and on every element of the set. HashSet<T> itself never passes null to the comparer's GetHashCode, so with a comparer such as StringComparer.OrdinalIgnoreCase the polyfill threw ArgumentNullException when the lookup value was null, or when the set contained null. It was also O(n) with a hash computed per element, even for a value that is not in the set.

Fix

Use Contains first, which is a hashed lookup and handles null the way the set does. Only when the value is present, scan for the stored instance using comparer.Equals alone (which is what the set itself calls for a null entry).

Test

TryGetValue_NullWithStringComparer uses an OrdinalIgnoreCase set containing null, and checks a case-insensitive hit returns the stored instance, a null lookup succeeds, a miss returns false, and a null lookup on a set without null returns false. It threw ArgumentNullException on net462 before the fix, and passes on net462 (polyfill), net48 and net10.0 (BCL).

@SimonCropp SimonCropp added this to the 11.4.4 milestone Oct 11, 2026
@SimonCropp
SimonCropp merged commit 7f4be06 into main Oct 11, 2026
5 checks passed
@SimonCropp
SimonCropp deleted the fix/hashset-trygetvalue branch October 11, 2026 22:12
This was referenced Oct 12, 2026
This was referenced Oct 13, 2026
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