检查 null 后出现空引用异常(检查 null 不起作用)

Pet*_*r82 2 .net c# ienumerable nullreferenceexception

看一下这段代码:

var categories = tokens.SelectMany(x => x.Categories);

if (categories != null)
{
    if (categories.Contains("interp")) //null ref exception
    {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试在类别中查找“interp”字符串时,出现空引用异常。所以看来“类别!= null”不起作用。

我找到了一些建议(这里How to check if IEnumerable is null orempty?),但它们涉及使用.Any()。但它只会使异常更早地准确(使用 .Any() 时)。甚至 ?.Any() 也会引发异常。

有任何想法吗?

Pan*_*vos 5

categories.Contains仅当 Categories属性为 null 时,此代码才会抛出 NRE 。

以下代码将抛出:

class Token
{
    public string[] Categories{get;set;}
}

var tokens=new []{new Token()};
var categories = tokens.SelectMany(x => x.Categories);
if (categories != null)
{
    if (categories.Contains("interp")) 
    {
        Console.WriteLine("Found");
    }
}
Run Code Online (Sandbox Code Playgroud)

但也会如此

tokens.SelectMany(x => x.Categories).ToArray();
Run Code Online (Sandbox Code Playgroud)

实际抛出的是SelectMany 内的嵌套迭代器,而不是ToArray()or Contains。该异常的堆栈跟踪是:

at System.Linq.Enumerable.<SelectManyIterator>d__17`2.MoveNext()
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value, IEqualityComparer`1 comparer)
at UserQuery.Main()
Run Code Online (Sandbox Code Playgroud)

SelectMany将尝试迭代每个Categories条目,发现该属性实际上为 null 并抛出。

Where快速解决方法是在前面添加一个SelectMany以消除空类别:

var categories = tokens.Where(x=>x.Categories!=null).SelectMany(x => x.Categories);
Run Code Online (Sandbox Code Playgroud)

真正解决方案是确保Categories永远不会为空 - 它应该在构造时初始化为空数组、列表等。重新分配时,绝不应将其设置为 null。

此示例将该_categories字段设置为,new string[0]即使调用者传递null到“类别”

class Token
{
    string[] _categories=new string[0];
    public string[] Categories{
        get => _categories;
        set => _categories = value??new string[0];
    }

}
Run Code Online (Sandbox Code Playgroud)

有了这个,Where(x=>x.Categories !=null)就不再需要了