[英]Safely dereferencing FirstOrDefault call in Linq c#
为了简洁起见,在我的代码中,我希望能够执行以下操作:拥有一个集合,找到匹配lambda表达式的第一个元素; 如果存在,则返回属性或函数的值。 如果它不存在,则返回null。
更新的例子w。 类
我们有一些东西
class Stuff
{
public int Id { get; set; }
public string Value { get; set; }
public DateTime? ExecutionTime { get; set; }
}
我的目标是在调用它时很好地返回
var list = new Stuff[] { new Stuff() { Id = 1, Value = "label", ExecutionTime = DateTime.Now } };
// would return the value of ExecutionTime for the element in the list
var ExistingTime = list.FirstOrDefault(s => s.Value.Contains("ab")).ExecutionTime;
// would return null
var NotExistingTime = list.FirstOrDefault(s => s.Value.Contains("zzz")).ExecutionTime;
是否可以使用一些linq-syntax-fu或者我必须在继续之前明确检查返回值?
原始例子w。 字符串
var stuff = {"I", "am", "many", "strings", "obviously"};
// would return "OBVIOUSLY"
var UpperValueOfAString = stuff.FirstOrDefault(s => s.contains("bvi")).ToUpper();
// would return null
var UpperValueOfAStringWannabe = stuff.FirstOrDefault(s => s.contains("unknown token")).ToUpper();
注释:我不应该在我的原始示例中使用字符串,因为它通过将其置于ToUpper方法和字符串类的中心稍微扭曲了问题。 请考虑更新的示例
为什么不这样做:
stuff.Where(s => s.contains("bvi"))
.Select(s => s.ToUpper())
.FirstOrDefault()
如果您有“非默认默认值”,则可以执行以下操作:
stuff.Where(s => s.contains("bvi"))
.Select(s => s.ToUpper())
.DefaultIfEmpty("Something Else")
.First()
我喜欢这个作为扩展方法:
public static U SelectMaybe<T, U>(this T input, Func<T,U> func)
{
if (input != null) return func(input);
else return default(U);
}
用法:
var UpperValueOfAString = stuff.FirstOrDefault(s => s.Contains("bvi")).SelectMaybe(x => x.ToUpper());
var UpperValueOfAStringWannabe = stuff.FirstOrDefault(s => s.Contains("unknown token")).SelectMaybe(x => x.ToUpper());
这将链返回默认值(在这种情况下为null
,但对于该类型是正确的),或调用相关函数并返回该值。
更新:
根据问题澄清,您不需要任何额外的代码来实现您想要的。 只需使用where子句和select projection子句:
var theString = stuff
.Where(s => s.contains("unknown token"))
.Select(s => s.ToUpper())
.FirstOrDefault();
正如评论中所建议的那样( 并在另一个答案中通用 ),将ToUpper
调用包装在扩展方法中。 扩展方法归结为静态方法调用的语法糖,因此它们可以很好地处理空值。
static class StringExtensions { public static string PossiblyToUpper(this string s) { if (s != null) return s.ToUpper(); return null; } }
你的电话会变成:
var upperValueOfAStringWannabe = stuff .FirstOrDefault(s => s.contains("unknown token")) .PossiblyToUpper();
现在只讨论简单地支持单行样式代码的扩展方法是否比多行更具表现力 - 在一天结束时,表达代码的意图比代码看起来更重要。
就个人而言,我认为处理空值的扩展方法乍一看是令人困惑的,因为它们看起来像常规方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.