foreach中的c#8个不可为空的引用类型会生成奇数警告消息

foreach中的c#8个不可为空的引用类型会生成奇数警告消息,c#,c#-8.0,C#,C# 8.0,在编写以下代码时 foreach (var item in (IEnumerable)searchAndReplaceData.RadGridView.ItemsSource ?? Enumerable.Empty<object>()) { object test = item; ... 每次在可空的保存代码中确保项不为空?有没有更优雅的方法来处理这个问题?多亏了友好人士的评论,我可以更狭隘地定义这个问题 简短的回答是:是的,如果(item==null)

在编写以下代码时

 foreach (var item in (IEnumerable)searchAndReplaceData.RadGridView.ItemsSource ?? Enumerable.Empty<object>())
 {
      object test = item;
      ...

每次在可空的保存代码中确保项不为空?有没有更优雅的方法来处理这个问题?

多亏了友好人士的评论,我可以更狭隘地定义这个问题

简短的回答是:是的,如果(item==null)继续,您必须使该
检查以避免该警告并处于保存状态。

因为编译器并不总是像我预期的那样显示警告,所以这里的一些示例代码可以帮助其他人理解空引用检查的当前限制。尤其是在使用第三方代码时,该代码尚未检查空引用

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());
        }
    }
}
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用制度;
#可空禁用
公共静态类NullableDisabled3rdPartyClass
{
公共静态对象UnclearnableStateEnumerableObject()
{
IEnumerable objects=新对象[]{1,2,3,null};
归还物品;
}
}
#可空启用
公共课程
{
公共静态void Main()
{
foreach(在(IEnumerable)nullabledDisabled3rdPartyClass.UnclearnableStateEnumerableLeasObject()中的var thing?Enumerable.Empty()
{
object item=thing;//显示警告CS8600
//Console.WriteLine(item.ToString());//崩溃
}
//不显示任何警告,但也会在thing.toString上崩溃
foreach(在(IEnumerable)nullabledDisabled3rdPartyClass.UnclearnableStateEnumerableLeasObject()中的var thing?Enumerable.Empty()
{
object item=thing;//无警告
//Console.WriteLine(thing.ToString());//崩溃
}
//也无济于事
var x=nullabledDisabled3rdPartyClass.UnlearnableStateEnumerableAleasObject()作为IEnumerable;
foreach(x??Enumerable.Empty()中的var thing)
{
object item=thing;//无警告
//Console.WriteLine(item.ToString());//崩溃
}
//不显示任何警告,也不会崩溃
foreach(在(IEnumerable)nullabledDisabled3rdPartyClass.UnclearnableStateEnumerableLeasObject()中的var thing?Enumerable.Empty()
{
如果(thing==null)继续;
对象项=事物;
Console.WriteLine(item.ToString());
}
}
}

多亏了友好人士的评论,我可以更狭隘地定义这个问题

简短的回答是:是的,如果(item==null)继续,您必须使该
检查以避免该警告并处于保存状态。

因为编译器并不总是像我预期的那样显示警告,所以这里的一些示例代码可以帮助其他人理解空引用检查的当前限制。尤其是在使用第三方代码时,该代码尚未检查空引用

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());
        }
    }
}
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用制度;
#可空禁用
公共静态类NullableDisabled3rdPartyClass
{
公共静态对象UnclearnableStateEnumerableObject()
{
IEnumerable objects=新对象[]{1,2,3,null};
归还物品;
}
}
#可空启用
公共课程
{
公共静态void Main()
{
foreach(在(IEnumerable)nullabledDisabled3rdPartyClass.UnclearnableStateEnumerableLeasObject()中的var thing?Enumerable.Empty()
{
object item=thing;//显示警告CS8600
//Console.WriteLine(item.ToString());//崩溃
}
//不显示任何警告,但也会在thing.toString上崩溃
foreach(在(IEnumerable)nullabledDisabled3rdPartyClass.UnclearnableStateEnumerableLeasObject()中的var thing?Enumerable.Empty()
{
object item=thing;//无警告
//Console.WriteLine(thing.ToString());//崩溃
}
//也无济于事
var x=nullabledDisabled3rdPartyClass.UnlearnableStateEnumerableAleasObject()作为IEnumerable;
foreach(x??Enumerable.Empty()中的var thing)
{
object item=thing;//无警告
//Console.WriteLine(item.ToString());//崩溃
}
//不显示任何警告,也不会崩溃
foreach(在(IEnumerable)nullabledDisabled3rdPartyClass.UnclearnableStateEnumerableLeasObject()中的var thing?Enumerable.Empty()
{
如果(thing==null)继续;
对象项=事物;
Console.WriteLine(item.ToString());
}
}
}

枚举一个
IEnumerable
时似乎是这样的,因为在您发布的代码中,在.NET Core 3.0和.NET Framework中,枚举产生
对象
,而在.NET Core 3.1中,枚举产生
对象?
,这就是您收到警告的原因

IEnumerable
生成
object?
是有意义的,因为没有指示内容的可空性

如果您认为集合中可能确实存在
null
s,那么您需要决定如何处理它们。如果你只是想忽略它们,你可以过滤掉它们。这基本上等同于(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) {
   ...

请注意,可以编写各种帮助器方法来清理这类代码。

枚举
IEnumerable
时似乎就是这样,正如您发布的代码中所述,在.NET Core 3.0和.NET Framework中,枚举生成
对象
,而在.NET Core 3.1中,枚举会产生
对象?
,这就是为什么会出现警告

IEnumerable
生成
object?
是有意义的,因为没有指示内容的可空性

如果您认为确实存在
nullvar 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) {
   ...