Nullability mismatch in generic type parameter between two method arguments
我编写了以下扩展方法:
1
2 3 4 5 |
// using System.Collections.Generic;
internal static class TExtensions { |
并尝试按如下方式使用它:
1
2 3 |
var s = DateTime.Now.Hour < 15 ?“abcd” : null;
var hs = new HashSet<string>(); Console.WriteLine(s.In(hs)); |
编译器在最后一行给我一个警告:
CS8620 Argument of type ‘HashSet’ cannot be used for parameter ‘hs’ of type ‘HashSet’ in ‘bool TExtensions.In(string? val, HashSet? hs)’ due to differences in the nullability of reference types.
因为编译器将 T 类型参数解析为 s 或 string? 的类型;但散列集不是 HashSet<T>,它是可空 string (HashSet<string?>) 的散列集,而是不可空 string (HashSet<string>) 的散列集。
我可以通过package一个空检查来解决这个问题:
1
2 3 |
或将哈希集显式键入为具有可为空的元素:
1
|
但是有什么方法可以使用可为空的属性来允许这种情况吗?或者还有什么我可以在 In 扩展方法中改变的吗?
- 我会说警告正在发挥作用——请注意 hs.Contains(s) 有同样的问题。虽然这通过扩展方法的魔力”起作用”,但您不希望鼓励在 null 值上调用方法。充其量它看起来像一个错误,最坏的情况是它隐藏了一个实际的错误。当您确定它是有意的时,我会将它写为 s!.In(hs),它会在不检查的情况下抑制警告。 (另外,在通过泛型为每种类型添加扩展方法时要非常小心——至少考虑让你的类 internal 这样你的添加不会渗透到其他人的程序集中。)
In方法的第一个参数可以使用[AllowNull]属性:
1
|
internal static bool In< T >([AllowNull] this T val, HashSet< T > hs) => hs.Contains(val);
|
但是,正如您在问题中描述的那样,这里的实际问题是推断的泛型类型参数由 s In 方法将被称为 In<string?>,它要求哈希集为 HashSet<string?>。您必须告诉编译器使用 string 而不是 string?:s.In<string>(hs).
如果你可以约束到不可为空的引用类型,你可以使用这个:
1
|
internal static bool In< T >(this T? val, HashSet< T > hs) where T : class => val != null && hs.Contains(val);
|
对于值类型,实现将是:
1
|
internal static bool In< T >(this T? val, HashSet< T > hs) where T : struct => val.HasValue && hs.Contains(val.Value);
|
请注意,如果类型参数本身可以为空,则只有第一个版本(带有 [AllowNull] 属性)有效。
您当然可以使用 null-forgiving-operator 来关闭编译器,而不是更改扩展方法:s.In(hs!) 或 s!.In(hs).
来源:https://www.codenong.com/58846244/