> Luckily, since type constraints are part of the signature of the method and there is no ambiguity, I am allowed to make this overload.
This isn’t the case. It’s allowed because the question-mark syntax means two different things in value- and reference-type contexts. The signatures really look like this:
public static IEnumerable<TR> SelectNotNull<T, TR>(
this IEnumerable<T> source,
Func<T, TR> fn)
where TR : class // …and the nullability of TR is tracked by the compiler
public static IEnumerable<TR> SelectNotNull<T, TR>(
this IEnumerable<T> source,
Func<T, Nullable<TR>> fn)
where TR : struct
This is an allowable overload.