2012-04-11 6 views
5

Acabo de enterarme de yield return, me parece realmente agradable. Yo lo uso en un método como este:yield return al agregar valores al final de un IEnumerable existente

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

Sin embargo, tengo que cambiar este método para devolver algunas ValidationResults de un método de niño. Sin utilizar yield, el código se vería así:

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

¿Es posible volver a escribir esto utilizando yield?

+0

Tenga en cuenta que no haya escrito correctamente "arbitraria". –

+0

@EricLippert Hah, de hecho. Deletreo esto mal todo el tiempo. En este caso, solo es una regla de validación de ejemplo ya que todavía no he resuelto los 'reales'. – Oliver

Respuesta

3

¿Estás buscando esto?

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

Si es así, creo que la primera versión se ve mejor.

+0

Gracias por esto. ¿Es necesario el 'salto de rendimiento'? – Oliver

+0

No, lo eliminaré. –

2

Sure. Simplemente use esto:

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

Después de eso, también puede continuar con rendimientos de rendimiento. Para que pueda devolver su retVal después de llamar al método y luego continuar como en su primera muestra. De esta manera:

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" }); 
    //... 
} 
2

Las otras soluciones publicadas hasta ahora son buenas. Aquí hay otra manera de resolver su problema:

  • Cree dos secuencias
  • concatenar
  • retorno de la concatenación.

Así:

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" }); 
    ... 
} 
Cuestiones relacionadas