看看下面的代码:
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()也会引发异常。
有什么想法吗?
答案 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;
}