在处理Nullable类型时在LinQ中使用.HasValue(),有没有办法摆脱“可能的SystemInvalidException”?

问题描述:

我有一个列表Foo's在处理Nullable类型时在LinQ中使用.HasValue(),有没有办法摆脱“可能的SystemInvalidException”?

Foo有型DateTime?

CreateDate我想要得到的最古老的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; 
    } 
} 
+1

当没有任何值的结果时,你想要结果是什么? (一个简短但完整的程序会在这里帮助...) – 2012-03-19 15:38:52

+0

如果没有,最老的可以是DateTime.MaxValue。 – radbyx 2012-03-19 15:40:29

+0

我的观点是:你如何期望'Min()'知道? – 2012-03-19 15:41:41

万一你“重新仍然坚持,你可能要考虑使用DefaultIfEmpty - 看看这可以帮助:

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

认为你要使用GetValueOrDefault之内,否则如果第一个查询完全没有返回结果,您将会仍然有问题。

+0

哈!真棒。来自树木的森林。 – dwerner 2012-03-19 15:59:31

+0

它说那个oldestFoo的类型是DateTime?我可以将查询转换为(DateTime),但是我仍然有SystemInvalidException。只有我吗? – radbyx 2012-03-19 16:08:43

+0

@radbyx:道歉 - 我在'选择'中有一个错误。将解决。 – 2012-03-19 16:14:17

可以使用GetValueOrDefault方法,该方法不会引起异常,并且有在这一点上没有空值,结果是一样的:

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

你也可以放心,在这种情况下演员阵容不会失败吗? 'select(DateTime)f.CreateDate',因为你已经通过'HasValue'确保它有一个值。 – dwerner 2012-03-19 15:42:33

+0

@dwerner:即使您知道在那一点上没有空值,编译器也不知道这一点。它没有对代码进行足够的分析,以认识到'HasValue'条件在代码的另一部分中清除了空值。 – Guffa 2012-03-19 15:45:41

+0

用GetValueOrDefault(DateTime.MaxValue)编辑它,我认为是正确的? – radbyx 2012-03-19 15:46:43

DateTime oldestFoo = 
    (from f in allFoos select f.CreateDate).Min() ?? DateTime.MaxValue; 

或者稍微更简洁:

DateTime oldestFoo = 
    allFoos.Select(f => f.CreateDate).Min() ?? DateTime.MaxValue; 

我的建议是调用Min前项目DateTime?DateTime

这里有一个Nullable<int>样品,做项目int来说明MinMax附加功能如何与可空INT的空和不同的名单的行为。

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 

代替在FOOS列表过滤DateTime?实例只有那些具有值,允许Min延伸到与DateTime?值工作,而不是投射到DateTime。当你有一个空的列表(如上面的例子),你会从Min而不是InvalidOperationException得到一个null值。