c# 8 foreach 中的 NonNullable 引用类型产生奇怪的警告消息
c# 8 NonNullable Reference Types in foreach produce odd warning message
写以下代码时
foreach (var item in (IEnumerable)searchAndReplaceData.RadGridView.ItemsSource ?? Enumerable.Empty<object>())
{
object test = item;
...
我收到一条关于行 object test=item;
:
的警告
CS 8600: Converting null literal or possible null value to non-nullable type.
你会如何处理这种情况?我必须写一个
if (item==null) continue;
每次在nullable-save代码中确保item不为null?有没有更优雅的方式来处理这个问题?
多亏了好心人的评论,我才可以更细化问题的定义。
简短的回答是:是的,您必须进行 if (item==null) continue;
检查以避免该警告并保持安全。
由于编译器并不总是显示警告 - 至少我所期望的,这里有一些示例代码可以帮助其他人理解空引用检查的当前限制。特别是在使用尚未检查空引用的第 3 方代码时。
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
#nullable disable
public static class NullableDisabled3rdPartyClass
{
public static object UnclearNullableStateEnumerableAsObject()
{
IEnumerable<object> objects = new object[] { 1, 2, 3, null };
return objects;
}
}
#nullable enable
public class Program
{
public static void Main()
{
foreach (var thing in (IEnumerable)NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() ?? Enumerable.Empty<object>())
{
object item = thing; //Shows the warning CS8600
//Console.WriteLine(item.ToString()); //crashes
}
//does not show any warning but also crashes on thing.toString
foreach (var thing in (IEnumerable<object>)NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() ?? Enumerable.Empty<object>())
{
object item = thing; //no warning
//Console.WriteLine(thing.ToString()); //crashes
}
//does not help either
var x = NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() as IEnumerable<object>;
foreach (var thing in x ?? Enumerable.Empty<object>())
{
object item = thing; //no warning
//Console.WriteLine(item.ToString()); //crashes
}
//shows no warning and does not crash
foreach (var thing in (IEnumerable)NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() ?? Enumerable.Empty<object>())
{
if (thing == null) continue;
object item = thing;
Console.WriteLine(item.ToString());
}
}
}
枚举 IEnumerable
时的情况似乎与您在 .NET Core 3.0 和 .NET Framework 中发布的代码一样,枚举产生 object
,而在 .NET Core 中3.1 枚举产生 object?
,这就是您收到警告的原因。
从 IEnumerable
产生 object?
确实有意义,因为没有迹象表明内容的可空性。
如果您认为集合中可能确实有 null
,那么您需要决定如何处理它们。如果你只是想忽略它们,你可以过滤掉它们。这基本上等同于您的 if (item == null) continue;
行。
var maybeSource = (IEnumerable<object?>?)searchAndReplaceData.RadGridView.ItemsSource;
var maybeNullItems = maybeSource ?? Enumerable.Empty<object?>();
var items = maybeNullItems.Where(maybeNullItem => maybeNullItem != null);
// items is automatically inferred to be IEnumerable<object>
foreach (var item in items) {
...
或者如果您认为任何项目实际上都不可能是 null
,您应该改为抛出(这样您会立即知道 if/when 您错了)。
var maybeSource = (IEnumerable<object?>?)searchAndReplaceData.RadGridView.ItemsSource;
var maybeNullItems = maybeSource ?? Enumerable.Empty<object?>();
var someAreNull = maybeNullItems.Any(maybeNullItem => maybeNullItem == null);
if (someAreNull)
throw new ShouldNotBeNullException(); // made-up exception for this purpose
var items = (IEnumerable<object>)maybeNullItems;
foreach (var item in items) {
...
请注意,可以编写各种辅助方法来大量清理此类代码。
写以下代码时
foreach (var item in (IEnumerable)searchAndReplaceData.RadGridView.ItemsSource ?? Enumerable.Empty<object>())
{
object test = item;
...
我收到一条关于行 object test=item;
:
CS 8600: Converting null literal or possible null value to non-nullable type.
你会如何处理这种情况?我必须写一个
if (item==null) continue;
每次在nullable-save代码中确保item不为null?有没有更优雅的方式来处理这个问题?
多亏了好心人的评论,我才可以更细化问题的定义。
简短的回答是:是的,您必须进行 if (item==null) continue;
检查以避免该警告并保持安全。
由于编译器并不总是显示警告 - 至少我所期望的,这里有一些示例代码可以帮助其他人理解空引用检查的当前限制。特别是在使用尚未检查空引用的第 3 方代码时。
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
#nullable disable
public static class NullableDisabled3rdPartyClass
{
public static object UnclearNullableStateEnumerableAsObject()
{
IEnumerable<object> objects = new object[] { 1, 2, 3, null };
return objects;
}
}
#nullable enable
public class Program
{
public static void Main()
{
foreach (var thing in (IEnumerable)NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() ?? Enumerable.Empty<object>())
{
object item = thing; //Shows the warning CS8600
//Console.WriteLine(item.ToString()); //crashes
}
//does not show any warning but also crashes on thing.toString
foreach (var thing in (IEnumerable<object>)NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() ?? Enumerable.Empty<object>())
{
object item = thing; //no warning
//Console.WriteLine(thing.ToString()); //crashes
}
//does not help either
var x = NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() as IEnumerable<object>;
foreach (var thing in x ?? Enumerable.Empty<object>())
{
object item = thing; //no warning
//Console.WriteLine(item.ToString()); //crashes
}
//shows no warning and does not crash
foreach (var thing in (IEnumerable)NullableDisabled3rdPartyClass.UnclearNullableStateEnumerableAsObject() ?? Enumerable.Empty<object>())
{
if (thing == null) continue;
object item = thing;
Console.WriteLine(item.ToString());
}
}
}
枚举 IEnumerable
时的情况似乎与您在 .NET Core 3.0 和 .NET Framework 中发布的代码一样,枚举产生 object
,而在 .NET Core 中3.1 枚举产生 object?
,这就是您收到警告的原因。
从 IEnumerable
产生 object?
确实有意义,因为没有迹象表明内容的可空性。
如果您认为集合中可能确实有 null
,那么您需要决定如何处理它们。如果你只是想忽略它们,你可以过滤掉它们。这基本上等同于您的 if (item == null) continue;
行。
var maybeSource = (IEnumerable<object?>?)searchAndReplaceData.RadGridView.ItemsSource;
var maybeNullItems = maybeSource ?? Enumerable.Empty<object?>();
var items = maybeNullItems.Where(maybeNullItem => maybeNullItem != null);
// items is automatically inferred to be IEnumerable<object>
foreach (var item in items) {
...
或者如果您认为任何项目实际上都不可能是 null
,您应该改为抛出(这样您会立即知道 if/when 您错了)。
var maybeSource = (IEnumerable<object?>?)searchAndReplaceData.RadGridView.ItemsSource;
var maybeNullItems = maybeSource ?? Enumerable.Empty<object?>();
var someAreNull = maybeNullItems.Any(maybeNullItem => maybeNullItem == null);
if (someAreNull)
throw new ShouldNotBeNullException(); // made-up exception for this purpose
var items = (IEnumerable<object>)maybeNullItems;
foreach (var item in items) {
...
请注意,可以编写各种辅助方法来大量清理此类代码。