在单个LINQ表达式中嵌入null测试

Bar*_*aye 4 c# linq null nullable

让我们从一个简单的示例类开始:

public class Foo
{
    public DateTime Date { get; set; }
    public decimal Price { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个列表:

List<Foo> foos = new List<Foo>;
Run Code Online (Sandbox Code Playgroud)

我想根据日期返回列表中一个项目的格式化价格或"N/A",例如我可以写:

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

我想上面的两行合并类似以下内容:

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

但是,这并没有达到我想要的效果,因为如果(f => f.Date == DateTime.Today)不返回Foo则NullReferenceException抛出a.

因此,LINQ是否可以创建1个语句来返回格式化的价格或"N/A"?

All*_*nek 10

如果先过滤然后选择,则可以使用null合并运算符(??),如下所示:

string price = foos.Where(f => f.Date == DateTime.Today)
                   .Select(f => f.Price.ToString())
                   .FirstOrDefault() ?? "N/A";
Run Code Online (Sandbox Code Playgroud)


Gro*_*roo 5

一种方法FirstOrDefault是在调用之前简单地检查结果是否为null ToString:

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

另一种方法是为合并运算符创建一个扩展方法,该方法也接受一个投影委托,如:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样调用它:

var s = foos
         .FirstOrDefault(f => f.Date == DateTime.Today)
         .Coalesce(t => t.Price.ToString("0.00"), "N/A");
Run Code Online (Sandbox Code Playgroud)