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

问题描述 投票:1回答:4

看看这段代码:

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

if (categories != null)
{
    if (categories.Contains("interp")) //null ref exception
    {
        return null;
    }
}

当我尝试在类别中找到“interp”字符串时,我得到Null Reference Exception。所以似乎“categories!= null”似乎不起作用。

我找到了一些建议(这里是How to check if IEnumerable is null or empty?),但它们涉及使用.Any()。但它只能使异常更早(使用.Any()时)。甚至?.Any()抛出异常。

有任何想法吗?

c# .net ienumerable nullreferenceexception
4个回答
4
投票

仅当Categories属性为null时,此代码才会在categories.Contains中抛出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");
    }
}

但是会这样

tokens.SelectMany(x => x.Categories).ToArray();

实际抛出的东西是SelectMany中的嵌套迭代器,而不是ToArray()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()

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

快速解决方法是在Where之前添加SelectMany以消除null类别:

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

真正的解决方案是确保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];
    }

}

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


3
投票

使用集合时,IEnumerable<T>避免使用null;如果你没有什么可以返回,返回一个空集合(不是null)。

在你的特殊情况下,SelectMany将永远不会返回null,但空集合,这就是为什么categories != null检查是无用的,你必须检查tokens而不是

if (null != tokens)
  // Where(x => x != null) - to be on the safe side if x == null or x.Categories == null
  if (tokens
       .Where(x => x != null && x.Categories != null)
       .SelectMany(x => x.Categories)
       .Contains("interp"))
    return null;

但是,不断检查null会导致代码无法读取,这就是为什么尝试检查null一次:

// if tokens is null change it for an empty collection
tokens = tokens ?? new MyToken[0];

...

if (tokens 
      .Where(x => x != null && x.Categories != null)
      .SelectMany(x => x.Categories)
      .Contains("interp"))
    return null;

0
投票

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

添加.ToList(),你应该知道更多关于错误在哪里与我们在帖子中的信息,我们只能猜测


0
投票

可以使用where子句并将其作为列表,然后只检查列表中是否有任何元素

 var categories = list.Where(x => x.Categories.Contains("interp")).ToList();
 if (categories.Count() == 0)
  {
     return null;

   }
© www.soinside.com 2019 - 2024. All rights reserved.