Хороший способ обработки исключения NullReferenceException до С# 6.0
Мой код ниже дает мне NullReferenceException
, и трассировка стека говорит мне, что проблема заключается в методе Count
, поэтому я уверен, что в какой-то момент foo
, bar
или baz
есть null
.
Мой код:
IQueryable<IGrouping<string, Referral>> queryable= ...;
var dict = queryable.ToDictionary(g => g.Key.ToString(),
g => g.Count(r => r.foo.bar.baz.dummy == "Success"));
Мне интересно, какой краткий способ обрабатывать случаи null
.
Я узнаю, что в С# 6.0 я могу просто сделать foo?.bar?.baz?.dummy
, однако проект, над которым я работаю, не является С# 6.0
Ответы
Ответ 1
Решением для < 6,0 будет:
.Count(r => r.foo != null &&
r.foo.bar != null &&
r.foo.bar.baz != null &&
r.foo.bar.baz.dummy == "Success")
Именно для сложных конструкций, подобных тому, что было введено выше оператора нулевого распространения, был введен.
Кроме того, вы также можете реорганизовать выражение в частный метод:
private Expression<Func<Referral, bool>> Filter(string value)
{
return r => r.foo != null &&
r.foo.bar != null &&
r.foo.bar.baz != null &&
r.foo.bar.baz.dummy == value;
}
и используйте его следующим образом:
g => g.Count(Filter("Success"))
Ответ 2
Вы можете использовать следующие методы расширения.
public static TResult With<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
where TResult : class
where TInput : class
{
return o == null ? null : evaluator(o);
}
public static TResult Return<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
return o == null ? failureValue : evaluator(o);
}
Их комбинация дает вам приятный, читаемый API для обработки nulls
:
return foo
.With(o => o.bar)
.With(o => o.baz)
.Return(o => o.dummy, null);
Ответ 3
Проблема в том, что метод ToDictionary
на самом деле не выполняется на запросе - вместо этого вы получаете всю коллекцию и выполняете агрегацию в своем приложении, а не на сервере БД.
Поэтому вместо прямого использования ToDictionary
сначала используйте Select
:
IQueryable<IGrouping<string, Referral>> queryable= ...;
var dict = queryable.Select(g => new { Key = g.Key.ToString(),
Count = g.Count(r => r.foo.bar.baz.dummy == "Success") })
.ToDictionary(i => i.Key, i => i.Count);
Это позволит убедиться, что агрегация выполняется в базе данных (где вам не нужны эти значения), а не в коде С# (где вы получаете NullReferenceException
).
Конечно, это предполагает, что запрос, который вы используете, представляет собой запрос БД (или, точнее, запрос, который поддерживает агрегацию и имеет ANUL SQL-подобную семантику NULL). Если у вас есть другой настраиваемый запрос, он не поможет (если вы явно не добавляете эти семантики NULL самостоятельно).
Ответ 4
// if null, use null
if(objectvariable == null)
{
// throw exception
}
// if not null
if(objectvariable != null)
{
// continue
}