Используя .HasValue () в LinQ при работе с типом Nullable, есть ли способ избавиться от «Возможного исключения SystemInvalidException»? - PullRequest
0 голосов
/ 19 марта 2012

У меня есть список Foo's.

Foo имеет CreateDate типа DateTime?

Я хочу получить самую старую Foo.Я пробовал интуитивно понятным способом, но получаю возможное System.InvalidOperationException.

DateTime oldestFoo = 
(from f in allFoos where f.CreateDate.HasValue select f.CreateDate.Value).Min(); 

Есть ли что-то, что я пропустил или это просто невозможно?

Я могу сделать это без LinQ таким образом, но я хочу изучить и другой подход.

DateTime oldestFoo = DateTime.MaxValue;
foreach (var foo in allFoos)
{
    if (foo.CreateDate.HasValue && oldestFoo > foo.CreateDate)
    {
        oldestFoo = (DateTime)foo.CreateDate;
    }
}

Ответы [ 4 ]

11 голосов
/ 19 марта 2012

На случай, если вы все еще застряли, вы можете рассмотреть возможность использования DefaultIfEmpty - посмотрите, поможет ли это:

DateTime oldestFoo = allFoos.Where(f => f.CreateDate.HasValue)
                            .Select(f => f.CreateDate.Value)
                            .DefaultIfEmpty(DateTime.MaxValue)
                            .Min();

Я не думаю, что вы хотите использовать GetValueOrDefault в своем запросе, иначе у вас будет все еще проблема, если первый запрос не даст результатов вообще.

1 голос
/ 19 марта 2012
DateTime oldestFoo =
    (from f in allFoos select f.CreateDate).Min() ?? DateTime.MaxValue;

Или, более кратко:

DateTime oldestFoo =
    allFoos.Select(f => f.CreateDate).Min() ?? DateTime.MaxValue;
1 голос
/ 19 марта 2012

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

DateTime oldestFoo = (
  from f in allFoos
  where f.CreateDate.HasValue
  select f.CreateDate.GetValueOrDefault()
).Min();
0 голосов
/ 19 марта 2012

Мое предложение - НЕ для проецирования DateTime? на DateTime перед вызовом Min.

Вот пример Nullable<int>, который не проецирует на int, чтобы показать, как расширения Min и Max ведут себя с пустыми и различными списками обнуляемых целых чисел.

var foo = Enumerable.Empty<int?>();
Console.WriteLine(foo.Min());

foo = new int? [] { null, -20, 10 };
Console.WriteLine(foo.Min());
Console.WriteLine(foo.Max());

Вывод выше:

null 
-20
10

Вместо фильтрации экземпляров DateTime? в списке Foos только для тех, у которых есть значения, разрешите расширению Min работать со значениями DateTime? вместо проецирования на DateTime. Если у вас есть пустой список (как в примере выше), вы получите null значение из Min вместо InvalidOperationException.

...