Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Linq c中安全地解除对FirstOrDefault调用的引用#_C#_Linq_Syntax - Fatal编程技术网

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

C# 在Linq c中安全地解除对FirstOrDefault调用的引用#,c#,linq,syntax,C#,Linq,Syntax,为了简洁起见,在我的代码中,我希望能够做到以下几点:拥有一个集合,找到与lambda表达式匹配的第一个元素;如果存在,则返回属性或函数的值。如果不存在,则返回null 更新了示例w。课程 var stuff = {"I", "am", "many", "strings", "obviously"}; // would return "OBVIOUSLY" var UpperValueOfAString = stuff.FirstOrDefault(s => s.contains("bvi

为了简洁起见,在我的代码中,我希望能够做到以下几点:拥有一个集合,找到与lambda表达式匹配的第一个元素;如果存在,则返回属性或函数的值。如果不存在,则返回null

更新了示例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();
让我们收集一些东西

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语法,或者在继续之前必须显式检查返回值

原始示例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方法和string类上,从而略微扭曲了问题。请考虑更新的例子

< P> <强>更新:< /强>

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

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

旧答案

按照注释()中的建议,将
ToUpper
调用包装在扩展方法中。扩展方法归结为围绕静态方法调用的语法糖,因此它们可以很好地处理null

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();
现在讨论的只是简单支持单行代码的扩展方法是否比多行代码更具表现力——说到底,表达代码的意图比代码的外观更重要


我个人认为处理空值的扩展方法乍一看是令人困惑的,因为它们被糖化成了常规方法。

我喜欢这样的扩展方法:

public static U SelectMaybe<T, U>(this T input, Func<T,U> func)
{
    if (input != null) return func(input);
    else return default(U);
}
这将返回默认值(
null,在本例中,但对于该类型是正确的),或者调用相关函数并返回该值。

为什么不:

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

也许可以在
ToUpper()
之前编写一些可以替代使用的扩展方法?例如,可以将
null
转换为
string.Empty
。这就是我的想法:我可以创建一个Func(fodt=>fodt!=null?fodt.property:null);函数并将FirstOrDefault调用包装在其中,我想知道是否确实有一些更干净的东西,但它增加了价值-我很高兴+1有人改进了内容。是的,这非常好,非常适合我的大多数情况;我可能也会将默认值作为lambda传递,但它很简单且有用。感谢您,我已将名称更改为
SelectMaybe
,因为它实际上只是一个检查
null
Select
。您可以添加重载来提供要返回的默认值,或者提供要测试的谓词。然而,衙门提出的建议可能要多才多艺得多。非常感谢。anyway@samy没问题,是的,我同意通用解决方案非常好。我已经抓到它了!:-)这取决于你“为你做那件事”的意思。同样的结果可以用不同的方法得到。.Select(x=>x.ToUpper())通过使用Where-before-to-filter可以很好地实现这一点,它只会将返回的结果大写,如果返回的结果为空,它将不起任何作用。和第一个默认值()。唯一不好的是,大写字母将所有过滤项都大写,而不是第一个字母onyl。@MarinoŠimić我已经删除了该语句。@MarinoŠimić这就是我在评论中询问Ani的答案。它看起来可能不多,但由于集合可能非常大,我希望避免这种开销。+1,这确实是一种只使用linq扩展的好方法。where是否存在问题,即每次调用时都会分析整个集合,即使集合中很早就有一个项与谓词匹配?@samy否,如果有第一个项,则最终的
FirstOrDefault
将在第一个项上停止迭代。上面的linq都不需要完整的列表解析才能工作,它都被推迟了。@Samy:不,我刚才问过。看,没错。在调用
First或default
(或
First
)之前,不会迭代任何内容。然后,元素只在链中迭代,直到返回一个。从这个意义上讲,它是有效的。你可以通过在
的Where
Select
中加入一个副作用,并看到它只会迭代,直到第一个匹配为止,来测试自己。让人大吃一惊的是!)@蒂姆·施梅尔特:非常感谢你的这篇启发性的文章。