2012-03-19 50 views
0

我有一個列表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

回答

10

萬一你「重新仍然堅持,你可能要考慮使用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

1

可以使用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

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

或者稍微更簡潔:

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

我的建議是調用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值。

相關問題