Другое взятие на FirstOrDefault

Мы следуем за trunk=current потоком разработки, branch=release (s) подход. На выпуске клиенту мы переходим соединительная линия и просто сохраняем соединительную линию продвигающейся вперед. Необходимо будет принять решение на том, сколько выпусков Вы готовы поддерживать. Чем больше Вы поддерживаете, тем больше слияния Вы будете делать на исправлениях ошибок. Мы пытаемся сохранить наших клиентов на не больше, чем 2 выпусках позади соединительной линии. (Например, Dev = 1.3, поддерживаемые версии 1.2 и 1.1).

10
задан Aurequi 10 November 2009 в 15:35
поделиться

3 ответа

Вероятно, ваш код неверный; вы, вероятно, не рассмотрели все случаи.

Конечно, мы не можем знать, правильный или неправильный какой-либо код, пока у нас не будет спецификации. Итак, начните с написания однострочной спецификации:

" 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;
}

Всегда сначала пишите спецификацию, даже если это всего лишь одно предложение.

Первый элемент, соответствующий предикату, равен нулю, поэтому его следует вернуть.

Правильная реализация спецификации будет выглядеть так:

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;
}

Всегда сначала пишите спецификацию, даже если это всего лишь одно предложение.

Первый элемент, соответствующий предикату, равен нулю, поэтому его следует вернуть.

Правильная реализация спецификации будет выглядеть так:

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;
}

Всегда сначала пишите спецификацию, даже если это всего лишь одно предложение.

42
ответ дан 3 December 2019 в 13:32
поделиться

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;
}
5
ответ дан 3 December 2019 в 13:32
поделиться

Мне кажется разумным, если вы хотите настроить удобочитаемость вместо использования DefaultIfEmpty.

Вы также можете создать переопределение, которое использует лямбду, если создание значения по умолчанию дорого, создавая только в случае необходимости.

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;
}
-1
ответ дан 3 December 2019 в 13:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: