【问题标题】:Why can't I use a nullable tuple for a nullable generic parameter为什么我不能将可空元组用于可空泛型参数
【发布时间】:2021-03-08 10:10:47
【问题描述】:

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

但是,当我尝试过滤出如下所示的可空元组时,我收到编译器错误,即预期为不可空元组类型。 为什么此解决方案适用于所有常规类型但不适用于元组,我如何更改我的扩展方法以也适用于元组。

扩展方法:

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);

【问题讨论】:

  • (string?, int) 不是可以为空的元组,也许你打算这样做 (string?, int)?
  • 请注意,这不适用于所有值类型,不仅仅是元组。
  • @RandRandom 你是对的,(string?, int) 不是可空元组,但是过滤方法“选择器”产生可空元组 (string, int)?,然后产生编译器错误。
  • @Sweeper 是的,我在验证它是否影响所有值类型时似乎犯了一个错误,这就是为什么我认为它只会导致元组出现问题。
  • c# 中没有“可空引用类型”之类的东西 - 这就是每个引用类型都可以为空的区别,即使使用 c# 8 和“新" 特征类型 string? 不是 Nullable&lt;string&gt; 它只是“魔术”,编译器会警告你尝试将 null 分配给你没有明确声明它可能为 null 的东西,例如。 string str = null; 是完全有效的 c# 代码,您不必编写 string? str = null; 但如果您启用了 c#8 功能,您将收到第一个警告

标签: c# generics tuples nullable


【解决方案1】:

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

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

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

【讨论】:

  • 我正在使用启用了可为空引用类型的 C# 9。我曾希望我可以编写一种扩展方法来处理可空值类型和可空引用类型。然而,这似乎是不可能的
  • @Blu3Souls 确实;这将是对行为的更大改变,而不是仅仅通过注释来实现
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 2021-02-17
  • 2012-09-09
相关资源
最近更新 更多