在Linq中安全地解除引用FirstOrDefault调用c#

时间:2012-06-27 09:01:31

标签: c# linq syntax

为了简洁起见,在我的代码中,我希望能够执行以下操作:拥有一个集合,找到匹配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方法和字符串类上来略微扭曲问题。请考虑更新的示例

3 个答案:

答案 0 :(得分:32)

为什么不这样做:

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()

答案 1 :(得分:9)

我喜欢这个作为扩展方法:

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,但对于该类型是正确的),或者调用相关函数并返回该值。

答案 2 :(得分:4)

<强>更新

根据问题澄清,您不需要任何额外的代码来实现您想要的。只需使用where子句和select projection子句:

var theString = stuff
    .Where(s => s.contains("unknown token"))
    .Select(s => s.ToUpper())
    .FirstOrDefault();

<小时/> 旧答案

正如评论(and made generic in another answer)中所建议的那样,将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();

现在只讨论简单地支持单行样式代码的扩展方法是否比多行更具表现力 - 在一天结束时,表达代码的意图比代码看起来更重要等。

就我个人而言,我认为处理空值的扩展方法乍一看是令人困惑的,因为它们看起来像常规方法。