This code will throw an NRE in categories.Contains
only if the Categories property is null.
The following code will throw :
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");
}
}
But so would
tokens.SelectMany(x => x.Categories).ToArray();
The thing that actually throws is the nested iterator inside SelectMany, not ToArray()
or Contains
. The stack trace for that exception is :
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
will try to iterate over each Categories
entry, find that the property is actually null and throw.
The quick fix is to add a Where
before SelectMany
to eliminate null Categories :
var categories = tokens.Where(x=>x.Categories!=null).SelectMany(x => x.Categories);
The real solution is to ensure Categories
is never empty - it should be initialized to an empty array, list, whatever upon construction. When reassigned, it should never be set to null.
This example sets the _categories
field to new string[0]
even if a caller passes null
to Categories
class Token
{
string[] _categories=new string[0];
public string[] Categories{
get => _categories;
set => _categories = value??new string[0];
}
}
With that, Where(x=>x.Categories !=null)
is no longer necessary