выбор свойства из FirstOrDefault в случае, если FirstOrDefault возвращает значение null

Я хочу сделать следующее заявление:

var block = blocksById.FirstOrDefault(X => X.Value == tracResult.ID).Key

Мой вопрос заключается в том, как с этим справиться более правильно, если у меня есть нулевое значение FirstOrDefault. Я просто не чувствую, что if является единственным решением, которое может быть здесь...


person Night Walker    schedule 13.11.2013    source источник
comment
Когда вы используете FirstOrDefault, вы ожидаете, что возвращаемое значение может быть нулевым. Итак, прежде чем делать .key, вы должны проверить возвращаемое значение для null. Если нулевое значение в этом случае является неожиданным, вы должны использовать First() и обрабатывать исключение нулевой ссылки.   -  person Hossain Muctadir    schedule 13.11.2013
comment
значение FirstOrDefault заключается в том, что вы не получаете никакого результата, тогда нулевое значение будет удалено.. если или условный оператор - единственный способ сделать это..   -  person Vishal Sharma    schedule 13.11.2013


Ответы (1)


С момента появления нулевых условных операторов (?), это так же просто, как:

var block = blocksById.FirstOrDefault(X => X.Value == tracResult.ID)?.Key;

Имейте в виду, что в этом сценарии, даже если Value является int, block будет иметь тип Nullable<int> и, следовательно, может быть null.

Однако, если вы хотите присвоить значение по умолчанию, если возвращается null, вы можете использовать нулевой оператор объединения (??) выглядит следующим образом:

var block = blocksById.FirstOrDefault(X => X.Value == tracResult.ID)?.Key ?? 6;

Тем не менее, для более сложных операторов Select справедливо следующее...


Некоторое время назад...

Разделите его на Where и Select:

var block = blocksById.Where(x => x.Value == tracResult.ID)
                      .Select(x => x.Key)
                      .FirstOrDefault();

Таким образом, вы не получите NullRefferenceException, если FirstOrDefault вернет null.

В качестве альтернативы вы можете указать значение по умолчанию, например:

var block = blocksById.Where(x => x.Value == tracResult.ID)
                      .Select(x => x.Key)
                      .FirstOrDefault() ?? somedefaultvalue;

Или, как указано @Silvermind для типов, не допускающих значение NULL, до типов, допускающих значение NULL (int):

var block = blocksById.Where(x => x.Value == tracResult.ID)
                      .Select(x => (int?) x.Key)
                      .FirstOrDefault() ?? somedefaultvalue;

Обновление: некоторые люди, кажется, сомневаются в том, что это допустимый вариант использования, и утверждают, что проверку на нуль нужно выполнить позже в программе.

Хотя во многих случаях это так, это не всегда должно быть правдой, а если это так, то такой способ может быть более удобным.

Некоторые примеры:

//one liner, null check delegated (not my favorite): 
return SomeCalculatedValue(collection.Where(condition).Select(selection).FirstOrDefault());

//or a mapping (shown with default value):
var result = collection.Where(condition)
                       .Select(c => 
                           { 
                                Foo = c.Foo,
                                Bar = c.Bar
                           }).FirstOrDefault()) ?? new { Foo = "New", Bar = "Empty"};
person Stefan    schedule 13.11.2013
comment
если мой ключ int, его невозможно использовать ?? оператор. - person Night Walker; 13.11.2013
comment
@NightWalker: Верно, тогда FirstOrDefault вернется к default(int), что равно 0. Тогда вы можете пропустить часть оператора ??. - person Stefan; 13.11.2013
comment
@NightWalker Вы можете привести его к обнуляемому целому (int?) в выборе, потому что результат FirstOrDefault() тогда будет нулевым. - person Silvermind; 13.11.2013