Рефакторинг yield return в операторе if

В проекте у меня есть набор объектов валидатора, из которых Validate yield возвращает ValidationResult для каждой ошибки. В свою очередь, они собираются, и создается исключение. Я украл это отсюда: Проверка: как внедрить оболочку состояния модели с помощью Ninject?

Когда объект, который необходимо проверить, имеет сложные свойства, которые также необходимо проверить, я получаю такой неуклюжий код (моя проблема — цикл foreach):

public class MembershipValidator
{

    public override IEnumerable<ValidationResult> Validate(Membership entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }

        foreach (var result in userValidator.Validate(entity.User))
        {
            yield return result;
        }

    }
}

Где UserValidator в этом случае также имеет несколько операторов yield return (один из которых показан здесь):

public class UserValidator
{
    public override IEnumerable<ValidationResult> Validate(User entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException();
        }

        if (entity.BirthDate == DateTime.MinValue)
        {
            yield return new ValidationResult("User", "BirthDate is mandatory");
        }

    }
}

Есть ли способ написать код в «родительском» валидаторе более лаконично? Теперь он пронизан foreach петлями. Просто написание следующего кода строится, но не выполняется:

userValidator.Validate(entity.User);

И следующее не компилируется:

return userValidator.Validate(beschouwing.User);

person Aage    schedule 14.08.2014    source источник
comment
Почему нельзя вернуть IEnumerable<ValidationResult>? т.е. return userValidator.Validate(entity.User);   -  person Sergey Berezovskiy    schedule 14.08.2014
comment
@SergeyBerezovskiy См. обновленный вопрос, извините, я не ясно выразился. Выдает следующую ошибку: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. Или я что-то пропустил?   -  person Aage    schedule 14.08.2014
comment
Можете ли вы привести пример кода с родительским foreach? Кстати, вопросы о рефакторинге обычно задают на codereview.stackexchange.com.   -  person Sergey Berezovskiy    schedule 14.08.2014
comment
@SergeyBerezovskiy Обновленный вопрос. Спасибо за информацию, в следующий раз пойду.   -  person Aage    schedule 14.08.2014


Ответы (1)


Просто разделите проверку параметров (т.е. генерацию исключений) и получите результаты проверки двумя методами:

public override IEnumerable<ValidationResult> Validate(User entity)
{
    if (entity == null)        
        throw new ArgumentNullException();        

    return UserValidationIterator(entity);
}

private IEnumerable<ValidationResult> UserValidationIterator(User user)
{
    if (entity.BirthDate == DateTime.MinValue)
       yield return new ValidationResult("User", "BirthDate is mandatory");

    // other yields here
}

Вы можете использовать тот же подход с проверкой членства.

person Sergey Berezovskiy    schedule 14.08.2014
comment
Но это не избавляет от цикла foreach в валидаторе Membership, не так ли? (Я добавил классы в оба валидатора для ясности). - person Aage; 14.08.2014