C#应该有一个forone结构吗?(或者处理零或一个案件的最简洁方法是什么)

Ian*_*cer 1 c# ienumerable language-features

当处理一个包含none,一个或多个项的枚举时,foreach循环可以很容易地迭代它们,LINQ Select可以很容易地从枚举项目中项目.

        foreach (var attr in p.GetCustomAttributes().OfType<A>()) ...
Run Code Online (Sandbox Code Playgroud)

当处理包含none或只有一个项目的枚举时,事情会有点棘手.您可以使用相同的foreach循环,但不能确保只存在其中一个项目,并且它可能会执行多次.

您可以添加.Take(1)以清楚地表明您只需要一个并确保循环仅执行一次.但如果不止一个,那就不会抛出异常.

        foreach (var attr in ...().Take(1)) ...
Run Code Online (Sandbox Code Playgroud)

您可以事先添加一个检查,以确保只有一个,或者可能是一个新的代码合同来检查,但这是相当混乱的:

        Contract.Requires(p..GetCustomAttributes().OfType<A>().Count() < 2);
        foreach (var attr in p.GetCustomAttributes().OfType<A>()) ...
Run Code Online (Sandbox Code Playgroud)

您甚至可以创建一个新的扩展方法.ZeroOrOne<T>(),它返回枚举中的第一个元素,然后如果您要求更多,则抛出异常.

        foreach (var attr in ...().ZeroOrOne()) ...
Run Code Online (Sandbox Code Playgroud)

或者你可以摆脱循环,使用.SingleOrDefault()然后测试null,这在意图方面显然是最清楚的,并确保循环执行零次或一次但是更多的代码,它不那么"声明性"而且它不是"可组合":

            var attr =  p.GetCustomAttributes().OfType<A>().SingleOrDefault();
            if (attr != null)
            {
               ...
Run Code Online (Sandbox Code Playgroud)

那么问题是:人们更喜欢上述哪种(或其他建议)?为什么? 大多数习惯于程序代码的程序员自然会更喜欢这个if语句,但对于那些深入到函数式编程的人来说,你有更好的方法吗?

其他一些语言有清晰的技术来处理这个问题,例如F#的数组模式可以匹配零个,一个或多个,或者失败.是否存在foroneC#语言中的构造的情况,它等同于检查枚举中是否有零或一个然后执行它?

[这里的具体示例是获取自定义属性,其中属性已被标记为不允许多个,但问题更一般地是关于处理零/一个案例.]

Che*_*hen 5

显然我会选择SingleOrDefault因为:

(1)这是一种内置方法.我自己不需要编写额外的方法.先生ZeroOrOne<T>,你出去了.

(2)一个简单的例子:

 var attr =  source.SingleOrDefault();
 if (attr != null)
 {
   //do something to attr
 }
 else
 {
   //the source is empty
   //throw an exception or prompt the user or something equivalent
 }
Run Code Online (Sandbox Code Playgroud)

如果你使用其他解决方案,我担心你需要写另一个if声明来检查source.Count().SingleOrDefault获胜者也是如此.