看看这段代码:
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()抛出异常。
有任何想法吗?
仅当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)
了
使用集合时,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;
var categories = tokens.SelectMany(x => x.Categories).ToList();
添加.ToList(),你应该知道更多关于错误在哪里与我们在帖子中的信息,我们只能猜测
可以使用where
子句并将其作为列表,然后只检查列表中是否有任何元素
var categories = list.Where(x => x.Categories.Contains("interp")).ToList();
if (categories.Count() == 0)
{
return null;
}