17

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

4

3 回答 3

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()
于 2012-06-27T09:18:55.720 回答
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在这种情况下,但对于该类型是正确的),或者调用相关函数并返回它。

于 2012-06-27T09:17:56.550 回答
4

更新:

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

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

现在只是讨论简单支持单行样式代码的扩展方法是否比多行更具表现力 - 归根结底,表达代码的意图比代码的外观更重要。

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

于 2012-06-27T09:05:42.820 回答