Рефакторингът дава връщане в оператора 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