2011-10-12 34 views
4

讓我們先從一個簡單的例子類:嵌入在一個單一的LINQ表達式零測試

public class Foo 
{ 
    public DateTime Date { get; set; } 
    public decimal Price { get; set; } 
} 

然後創建一個列表:

List<Foo> foos = new List<Foo>; 

我想返回格式化的價格或「 N/A」的基礎上的日期列表的一個項目,這麼比如我可以這樣寫:

Foo foo = foos.FirstOrDefault(f => f.Date == DateTime.Today); 
string s = (foo != null) ? foo.Price.ToString("0.00") : "N/A"; 

我會LIK e將上述兩行合併如下:

string s = foos.FirstOrDefault(f => f.Date == DateTime.Today).Price.ToString("0.00") ?? "N/A"; 

然而,這並沒有達到我想要的,因爲如果(f => f.Date == DateTime.Today)不返回一個Foo然後NullReferenceException被拋出。

因此,是否有可能用LINQ創建1條語句來返回格式化的價格或「N/A」?

回答

10

如果過濾,然後再選擇,你可以使用空合併運算符(??)像這樣:

string price = foos.Where(f => f.Date == DateTime.Today) 
        .Select(f => f.Price.ToString()) 
        .FirstOrDefault() ?? "N/A"; 
+0

這個作品,但阿隆忘記了()後ToString –

+0

@MikeCheel:修正,謝謝。 –

+0

完全是我以後 - 謝謝你。 –

5

的一種方法是簡單地檢查是否的FirstOrDefault結果爲空,調用ToString之前:

var todayFoo = foos.FirstOrDefault(f => f.Date == DateTime.Today); 
var s = todayFoo != null ? todayFoo.Price.ToString("0.00") : "N/A"; 

另一種方式是一種用於合併運算符,其還接受投影委託創建擴展方法,是這樣的:

public static class ObjectExt 
{ 
    public static T2 Coalesce<T1, T2>(
     this T1 obj, Func<T1, T2> projection, T2 defaultValue) 
    { 
     if (obj == null) 
      return defaultValue; 

     return projection(obj); 
    } 
} 

然後調用它像這樣:

var s = foos 
     .FirstOrDefault(f => f.Date == DateTime.Today) 
     .Coalesce(t => t.Price.ToString("0.00"), "N/A"); 
+0

謝謝你 - 我真的很喜歡的擴展方法,但是,我只認爲Allon的解決方案對我來說更加簡潔和重要(儘管這不是要求),對於其他場景更通用。 –

+0

@Barry:我同意,Allon的解決方案比較簡單。 LINQ允許這樣做,因爲它的執行很懶,但是在其他情況下可以使用擴展方法(任何時候在訪問屬性之前需要合併)。 – Groo

+0

@Groo:實際上,這並不是因爲懶惰的評估 - 你可以在每次方法調用之後放置'.ToArray()'以防止懶惰評估,它仍然可以工作。這是由於操作的基於集合的本質,其中一個空集仍然是一個集合,因此投影不會拋出'NullReferenceException'。儘管如此,你的擴展方法非常有用。 –

2

string s = foos.Where(f => f.Date == DateTime.Today).Select(f => f.Price.ToString("0.00")).FirstOrDefault();