What's wrong
When no comparer is passed, the constructors of OrderedSet<T>, OrderedCollection<T> and OrderedMap<TKey,TValue> check whether T is comparable. The check is:
typeof(IComparable<T>).IsAssignableFrom(typeof(T)) || typeof(IComparable).IsAssignableFrom(typeof(T))
Nullable<U> implements neither interface, so the constructor rejects int?, DateTime? and similar types with:
ArgumentException: Type System.Nullable`1[System.Int32] must implement IComparable<T> or IComparable when no comparer is provided.
Comparer<int?>.Default does order these types correctly, with null first, and SortedSet<int?> accepts them.
Locations:
OrderedSet.cs: lines 73, 110 and 150
OrderedCollection.cs: the equivalent constructors (about lines 83 and 120)
OrderedMap: the primary-constructor field initializer, plus the capacity and dictionary constructors
Repro (reproduced)
new OrderedSet<int?>(); // throws ArgumentException
new OrderedCollection<int?>(); // throws
new OrderedMap<int?, string>(); // throws
new SortedSet<int?> { 3, null, 1 }; // fine, Count == 3
Why it matters
Sorting nullable values, such as optional dates or optional priorities, is common. Today it forces users to write a comparer that just wraps Comparer<T?>.Default, and nothing explains why.
Suggested fix
Move the check into one helper that tests the underlying type, and use it in every constructor of all three classes:
Type t = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
bool ok = typeof(IComparable<>).MakeGenericType(t).IsAssignableFrom(t) || typeof(IComparable).IsAssignableFrom(t);
Acceptance: all three containers can be constructed for int?, and they sort nulls the same way Comparer<int?>.Default does. Tests cover this.
What's wrong
When no comparer is passed, the constructors of
OrderedSet<T>,OrderedCollection<T>andOrderedMap<TKey,TValue>check whetherTis comparable. The check is:Nullable<U>implements neither interface, so the constructor rejectsint?,DateTime?and similar types with:Comparer<int?>.Defaultdoes order these types correctly, with null first, andSortedSet<int?>accepts them.Locations:
OrderedSet.cs: lines 73, 110 and 150OrderedCollection.cs: the equivalent constructors (about lines 83 and 120)OrderedMap: the primary-constructor field initializer, plus the capacity and dictionary constructorsRepro (reproduced)
Why it matters
Sorting nullable values, such as optional dates or optional priorities, is common. Today it forces users to write a comparer that just wraps
Comparer<T?>.Default, and nothing explains why.Suggested fix
Move the check into one helper that tests the underlying type, and use it in every constructor of all three classes:
Acceptance: all three containers can be constructed for
int?, and they sort nulls the same wayComparer<int?>.Defaultdoes. Tests cover this.