Подтвердить что ты не робот

Хороший способ обработки исключения 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

4b9b3361

Ответ 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  
}