我有这样的代码:
IEnumerable<string?> items = new [] { "test", null, "this" };
var nonNullItems = items.Where(item => item != null); //inferred as IEnumerable<string?>
var lengths = nonNullItems.Select(item => item.Length); //nullability warning here
Console.WriteLine(lengths.Max());如何以方便的方式编写这段代码:
不存在空性警告,因为IEnumerable<string>.
item! (因为我希望从编译器的正常检查中受益,而不依赖于我是一个无错误的编码器),因此推断为nonNullItems类型不需要添加运行时检查的非空断言(因为这在代码大小和运行时都是没有意义的开销,
。
我知道这个解决方案,它利用了C# 8.0编译器中的流敏感类型,但它是.不太漂亮,主要是因为它太长,太吵了:
var notNullItems = items.SelectMany(item =>
item != null ? new[] { item } : Array.Empty<string>())
);还有更好的选择吗?
发布于 2019-10-14 08:56:34
我认为你必须以某种方式帮助编译器。调用.Where()永远不会安全地返回null。也许微软可以添加一些逻辑来确定像你这样的基本场景,但AFAIK目前的情况并非如此。
但是,您可以编写这样一个简单的扩展方法:
public static class Extension
{
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> o) where T:class
{
return o.Where(x => x != null)!;
}
}发布于 2019-10-14 08:37:09
不幸的是,您将不得不告诉编译器,您比编译器更了解这种情况。
原因之一是Where方法没有以一种让编译器理解非空性保证的方式进行注释,实际上也不可能对其进行注释。可能需要在编译器中添加更多的启发式方法来理解一些基本的情况,比如这个,但是目前我们还没有。
因此,一种选择是使用无效的宽恕运算符,俗称“该死的运算符”。然而,您可以亲自讨论这个问题,而不是在使用集合的代码中到处洒上感叹号,相反,您可以在生成集合时增加一个额外的步骤,至少对我来说,这会使它更令人愉快:
var nonNullItems = items.Where(item => item != null).Select(s => s!);这将将nonNullItems标记为IEnumerable<string>而不是IEnumerable<string?>,因此在其余代码中将正确处理。
发布于 2019-10-22 18:56:22
我不知道这个答案是否符合你的第三个要点的标准,但是你的.Where()过滤器也不满足,所以.
替换
var nonNullItems = items.Where(item => item != null)
使用
var nonNullItems = items.OfType<string>()
这将为IEnumerable<string>生成一种推断类型的nonNullItems,这种技术可以应用于任何可为空的引用类型。
https://stackoverflow.com/questions/58372791
复制相似问题