yield return при добавлении значений в конец существующего IEnumerable

Я только что узнал о yield returnЯ, кажется, очень мило. Я использую его в таком методе:

public IEnumerable<ValidationResult> Validate(ValidationContext vc)
{
    if (Name == "Arbitary")
        yield return new ValidationResult("Bad Name.", new[] { "Name" });
    else if (Email == "BadEmail")
        yield return new ValidationResult("Bad Email.", new [] {"Email" });
    // further rules follow.
}

Однако мне нужно изменить этот метод, чтобы он возвращал некоторые ValidationResults из дочернего метода. Без использования yieldкод будет выглядеть так:

public override IEnumerable<ValidationResult> Validate(ValidationContext vc)
{
    // TryValidateObject fills the ICollection you pass it.
    List<ValidationResult> retVal = new List<ValidationResult>();
    Validator.TryValidateObject(this, vc, retVal, true);

    if (Name == "Arbitary")
        retVal.Add(new ValidationResult("Bad Name.", new[] { "Name" }));
    else if (Email == "BadEmail")
        retVal.Add(new ValidationResult("Bad Email.", new[] { "Email" }));

    return retVal;
}

Можно ли переписать это, используя yield?

3 ответа

Решение

Вы ищете это?

public override IEnumerable<ValidationResult> Validate(ValidationContext vc)
{
    // TryValidateObject fills the ICollection you pass it.
    List<ValidationResult> retVal = new List<ValidationResult>();
    Validator.TryValidateObject(this, vc, retVal, true);
    foreach (var item in retVal)
        yield return item;
    if (Name == "Arbitary")
        yield return new ValidationResult("Bad Name.", new[] { "Name" });
    else if (Email == "BadEmail")
        yield return new ValidationResult("Bad Email.", new[] { "Email" });       
}

Если так, то я считаю, что первая версия выглядит лучше.

Другие решения, опубликованные до сих пор, хороши. Вот еще один способ решить вашу проблему:

  • Создать две последовательности
  • объединить их
  • вернуть конкатенацию.

Так:

public override IEnumerable<ValidationResult> Validate(ValidationContext vc)
{
  return ResultsFromValidator(vc).Concat(AdditionalResults());
}
private IEnumerable<ValidationResult> ResultsFromValidator(ValidationContext vc)
{
  List<ValidationResult> retVal = new List<ValidationResult>();
  Validator.TryValidateObject(this, vc, retVal, true);
  return retVal;
}
private IEnumerable<ValidationResult> AdditionalResults()
{
  if (Name == "Arbitrary")
    yield return new ValidationResult("Bad Name.", new[] { "Name" });
  ...
}

Конечно. Просто используйте это:

foreach (var item in retVal) {
    yield return item;
}

После этого вы также можете продолжить с доходности. Таким образом, вы можете вернуть свой retVal после того, как вызвали метод, а затем продолжить, как в первом примере. Как это:

public override IEnumerable<ValidationResult> Validate(ValidationContext vc)
{
    List<ValidationResult> retVal = new List<ValidationResult>();
    Validator.TryValidateObject(this, vc, retVal, true);
    foreach (var item in retVal) {
        yield return item;
    }

    if (Name == "Arbitary")
        yield return new ValidationResult("Bad Name.", new[] { "Name" });
    else if (Email == "BadEmail")
        yield return new ValidationResult("Bad Email.", new[] { "Email" });
    //...
}
Другие вопросы по тегам