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

时间:2019-03-15 08:22:34

标签: c# .net ienumerable nullreferenceexception

看看下面的代码:

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

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

当我尝试在类别中找到“ interp”字符串时,我得到Null Reference Exception。因此,似乎“类别!= null”无效。

我找到了一些建议(在How to check if IEnumerable is null or empty?处),但其中涉及使用.Any()。但这只会使异常更早(在使用.Any()的情况下)成为准确。甚至?.Any()也会引发异常。

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

仅当类别属性为空时,此代码才会在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条目,发现该属性实际上为空并抛出。

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

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

real 解决方案是确保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)就不再需要

答案 1 :(得分: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;

答案 2 :(得分:0)

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

add .ToList(),您应该了解更多有关错误的位置 利用帖子中的信息,我们只能猜测

答案 3 :(得分:0)

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

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

   }