Let's start with a simple example class:
public class Foo
{
public DateTime Date { get; set; }
public decimal Price { get; set; }
}
Then create a list:
List<Foo> foos = new List<Foo>;
I would like to return a formatted price or "N/A" of one item in the list based on a date, so for example I could write:
Foo foo = foos.FirstOrDefault(f => f.Date == DateTime.Today);
string s = (foo != null) ? foo.Price.ToString(开发者_开发问答"0.00") : "N/A";
I would like to combine the above 2 lines like the following:
string s = foos.FirstOrDefault(f => f.Date == DateTime.Today).Price.ToString("0.00") ?? "N/A";
However, this does not achieve what I want because if (f => f.Date == DateTime.Today)
does not return a Foo then a NullReferenceException
is thrown.
Therefore, is it possible with LINQ to create just 1 statement to either return the formatted price or "N/A"?
If you filter first and then select, you can use the null coalescing operator (??
) like so:
string price = foos.Where(f => f.Date == DateTime.Today)
.Select(f => f.Price.ToString())
.FirstOrDefault() ?? "N/A";
One way would be to simply check if result of FirstOrDefault
is null, before calling ToString
:
var todayFoo = foos.FirstOrDefault(f => f.Date == DateTime.Today);
var s = todayFoo != null ? todayFoo.Price.ToString("0.00") : "N/A";
Another way would be to create an extension method for a coalescing operator which also accepts a projection delegate, something like:
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);
}
}
And then call it like this:
var s = foos
.FirstOrDefault(f => f.Date == DateTime.Today)
.Coalesce(t => t.Price.ToString("0.00"), "N/A");
string s = foos.Where(f => f.Date == DateTime.Today).Select(f => f.Price.ToString("0.00")).FirstOrDefault();
精彩评论