为什么我不能对可为空的泛型参数使用可为空的元组

Why can't I use a nullable tuple for a nullable generic parameter

所以我想知道您是否可以创建一个扩展方法,将 .Where().Select() 的功能结合起来,用于过滤掉列表的空值并保持类型一致的特殊情况与可空引用类型。这意味着如果我得到一个 string?[] 它将过滤掉所有 null 值和 return 一个没有可为空字符串的 IEnumerable<string>

但是,当我尝试如下所示过滤掉可为 null 的元组时,出现编译器错误,指出应为不可为 null 的元组类型。 为什么此解决方案适用于所有常规类型但不适用于元组,以及如何更改我的扩展方法以使其也适用于元组。

扩展方法:

public static IEnumerable<TResult> SelectNotNull<TSource, TResult>
(this IEnumerable<TSource> enumerable, Func<TSource, TResult?> selector)
{
    foreach (var item in enumerable)
        if (selector(item) is { } result)
            yield return result;
}

产生编译器错误的示例代码:

(string?, int)[] arr = Array.Empty<(string?, int)>();

static (string, int)? Selector((string?, int) x)
{
    return x.Item1 != null ? x : null;
}

arr.SelectNotNull<(string?, int), (string, int)>(Selector);

在没有约束的情况下,您的 TResult? 被解释为引用类型可空性注释(如果未启用引用类型可空性,您应该会看到 CS8632 警告,或者如果使用早期的 C#,则会出现硬错误编译器版本)- 可空性注释 非常 只是建议;他们不会改变任何艰难的行为。要使用值类型 获得您似乎想要的行为 ,您可以添加:

public static IEnumerable<TResult> SelectNotNull<TSource, TResult>
(this IEnumerable<TSource> enumerable, Func<TSource, TResult?> selector)
    where TResult : struct // <== add constraint

但是,这根本不适用于引用类型。