我有一个linq查询,需要从一行中提取日期列。表达式目前看起来像这样
myObject.OrderByDescending(s=> s.MyDate).Where(s => s.CRAStatus.Description == "CheckedOut").FirstOrDefault().MyDate)
问题是如果没有“CheckedOut”行,查询将返回null并尝试获取“MyDate”将引发异常。我们有一些冗长的解决方案,例如:
.ForMember(dest => dest.CheckOutDate, opt => opt.MapFrom(src => {
var temp = src.CRAStatusChangeEvents.OrderByDescending(s=> s.MyDate).Where(s => s.CRAStatus.Description == "CheckedOut").FirstOrDefault();
return temp == null ? temp.MyDate : null;
}));
但要找到更简洁的东西会更好。任何想法?
答案 0 :(得分:4)
为什么不
myObject.OrderByDescending(s=> s.MyDate)
.Where(s => s.CRAStatus.Description == "CheckedOut")
.Select(s => s.MyDate as DateTime?)
.FirstOrDefault();
或
myObject.Where(s => s.CRAStatus.Description == "CheckedOut")
.Max(s => s.MyDate as DateTime?);
答案 1 :(得分:3)
一个选项是将default if empty设置为“空”实例(想想string.Empty - 它是一个表示空结果的已知实例):
var date = (myObject
.OrderByDescending(s=> s.MyDate)
.Where(s => s.CRAStatus.Description == "CheckedOut")
.DefaultIfEmpty(MyObject.Empty)
.FirstOrDefault()).MyDate;
以下是一个显示其工作原理的摘录:
var strings = new string[]{"one", "two"};
var length =
(strings.Where(s=>s.Length > 5)
.DefaultIfEmpty(string.Empty)
.FirstOrDefault()).Length;
运行它,长度为0.删除DefaultIfEmpty行,你得到一个NRE。
答案 2 :(得分:1)
var checkedOut = myObject.Where(s => s.CRAStatus.Description == "CheckedOut");
if (checkedOut.Count() > 0) {
var result = checkedOut.Max(s=> s.MyDate).MyDate;
}
答案 3 :(得分:1)
扩展方法怎么样?
static class MyObjectEnumerableExtensions
{
public static TMember GetMemberOfFirstOrDefault<TMember>(this IEnumerable<MyObject> items, Func<MyObject, TMember> getMember)
{
MyObject first = items.FirstOrDefault();
if (first != null)
{
return getMember(first);
}
else
{
return default(TMember);
}
}
}
样本用法:
List<MyObject> objects = new List<MyObject>();
objects.Add(new MyObject { MyDate = DateTime.MinValue });
var filteredObjects = from s in objects where s.MyDate > DateTime.MinValue select s;
DateTime date = filteredObjects.GetMemberOfFirstOrDefault(s => s.MyDate);
Console.WriteLine(date);