Alternative Way To Write Yield

1.3k views Asked by At

Is there a way to get rid of the .FirstOrDefault() with the following setup. I love using the yield statement but I want to condense the IsRequired method to the point where I dont have to use .FirstOrDefault().

PlayerValidator

protected override IEnumerable<ValidationResult> Validate(PlayerModel entity, IValidationProvider validationProvider)
        {
            yield return ValidationResultHelper.IsRequired(entity.Profile.FirstName, "First Name").FirstOrDefault();

            if (string.IsNullOrWhiteSpace(entity.Profile.LastName))
                yield return new Required("Last Name");
        }

ValidatorHelper

public IEnumerable<ValidationResult> IsRequired(string text, string name)
{
    if (string.IsNullOrWhiteSpace(text))
        yield return new Required(name);
}
2

There are 2 answers

0
BrokenGlass On BEST ANSWER

foreach would be another option (and it wouldn't return erroneously null in the case that there is no validation error as in your example):

protected override IEnumerable<ValidationResult> Validate(PlayerModel entity, IValidationProvider validationProvider)
{
    foreach (var result in ValidationResultHelper.IsRequired(entity.Profile.FirstName, "First Name"))
        yield return result;
    if (string.IsNullOrWhiteSpace(entity.Profile.LastName))
        yield return new Required("Last Name");
}
0
ta.speot.is On

I'm not as familiar with yield return as I could be, but in this case I think the way you've used yield return in IsRequired is using the wrong tool for the job. I would structure it slightly differently:

ValidatorHelper

// Note this function is almost unnecessary and might be better
// implemented in AddIfRequired if validation is this trivial.
public static bool IsRequired(string text)
{
    return string.IsNullOrWhiteSpace(text);
}

PlayerValidator

private static void AddIfRequired(string text, string name, List<ValidationResult> validationResults)
{
    if (ValidatorHelper.IsRequired(text))
        requiredList.Add(new Required(name));
}

protected override IEnumerable<ValidationResult> Validate(PlayerModel entity, IValidationProvider validationProvider)
{
    List<ValidationResult> validationResults = new List<ValidationResult>();

    AddIfRequired(entity.Profile.FirstName, "First Name", validationResults);
    AddIfRequired(entity.Profile.LastName, "Last Name", validationResults);
    // ...

    return validationResults;
}

If you really want to use yield return and save yourself creating a list and validating all fields each time (although I don't think this would be a performance problem), you could make AddIfRequired into ValidationResultIfRequired and Validate into:

ValidationResult validationResult;

// ...

validationResult = ValidationResultIfRequired(entity.Profile.FirstName, "First Name");
if (validationResult != null)
    yield return validationResult;

validationResult = ValidationResultIfRequired(entity.Profile.LastName, "Last Name");
// etc