对 FirstOrDefault 的不同看法

发布于 2024-08-11 05:40:26 字数 338 浏览 6 评论 0原文

IEnumerable 扩展方法 FirstOrDefault 并没有完全按照我的意愿行事,因此我创建了 FirstOrValue。这是解决这个问题的好方法还是有更好的方法?

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
    T first = source.FirstOrDefault(predicate);
    return Equals(first, default(T)) ? value : first;
}

The IEnumerable extension method FirstOrDefault didn't exactly do as I wanted so I created FirstOrValue. Is this a good way to go about this or is there a better way?

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
    T first = source.FirstOrDefault(predicate);
    return Equals(first, default(T)) ? value : first;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谷夏 2024-08-18 05:40:26

您的代码可能不正确;您可能还没有考虑所有情况。

当然,在我们有规范之前,我们无法知道任何代码是否正确或不正确。因此,首先编写一个单行规范:

FirstOrValue 接受 T 序列、谓词和 T 值,并返回序列中与谓词匹配的第一项如果有的话,或者如果没有,则为规定值。”

您的尝试实际上实现了该规范吗?当然不是!测试一下:

int x = FirstOrValue<int>( new[] { -2, 0, 1 }, y=>y*y==y, -1);

返回-1。根据规范,正确答案是 0。与谓词匹配的第一个项目为零,因此应该返回它。

规范的正确实现如下所示:

public static T FirstOrValue<T>(this IEnumerable<T> sequence, Func<T, bool> predicate, T value)
{
    if (sequence == null) throw new ArgumentNullException("sequence");
    if (predicate == null) throw new ArgumentNullException("predicate");
    foreach(T item in sequence)
        if (predicate(item)) return item;
    return value;
}

始终先编写规范,即使它只是一个句子。

Your code is probably incorrect; you probably haven't considered all of the cases.

Of course, we cannot know if any code is correct or incorrect until we have a spec. So start by writing a one-line spec:

"FirstOrValue<T> takes a sequence of T, a predicate, and a value of T, and returns either the first item in the sequence that matches the predicate if there is one, or, if there is not, the stated value."

Does your attempt actually implement that spec? Certainly not! Test it:

int x = FirstOrValue<int>( new[] { -2, 0, 1 }, y=>y*y==y, -1);

this returns -1. The correct answer according to the spec is 0. The first item that matches the predicate is zero, so it should be returned.

A correct implementation of the spec would look like:

public static T FirstOrValue<T>(this IEnumerable<T> sequence, Func<T, bool> predicate, T value)
{
    if (sequence == null) throw new ArgumentNullException("sequence");
    if (predicate == null) throw new ArgumentNullException("predicate");
    foreach(T item in sequence)
        if (predicate(item)) return item;
    return value;
}

Always write a spec first, even if it's only a single sentence.

屋檐 2024-08-18 05:40:26

对于引用类型,default(T) 默认返回 null

我会这样做

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
    T first = source.FirstOrDefault(predicate);
    return first ?? value;
}

default(T) will return null by default for reference types.

I would do this

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
    T first = source.FirstOrDefault(predicate);
    return first ?? value;
}
此刻的回忆 2024-08-18 05:40:26

由于这是一个重载,因此值得一提的是没有谓词的版本。

public static T FirstOrValue<T>(this IEnumerable<T> sequence, T value)
{
    if (sequence == null) throw new ArgumentNullException("sequence");
    foreach(T item in sequence) 
        return item; 
    return value;
}

Since this is an overload, it's worth mentioning the version with no predicate.

public static T FirstOrValue<T>(this IEnumerable<T> sequence, T value)
{
    if (sequence == null) throw new ArgumentNullException("sequence");
    foreach(T item in sequence) 
        return item; 
    return value;
}
〗斷ホ乔殘χμё〖 2024-08-18 05:40:26

如果您想调整可读性而不是使用 DefaultIfEmpty,这对我来说似乎是合理的。

如果默认值的创建成本很高,您还可以创建使用 lambda 的覆盖,仅在必要时创建它。

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> getValue)
{
    T first = source.FirstOrDefault(predicate);
    return Equals(first, default(T)) ? getValue() : first;
}

Seems reasonable to me if you want to tweak the readability instead of using DefaultIfEmpty.

You could also create an override that uses a lambda if the creation of the default value is expensive, creating it only if necessary.

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> getValue)
{
    T first = source.FirstOrDefault(predicate);
    return Equals(first, default(T)) ? getValue() : first;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文