2009-06-25 11 views
8

Tengo un empleado de la clase. Quiero poder Validarlo() antes de guardarlo para asegurarme de que todos los campos se hayan rellenado con valores válidos. El usuario de la clase puede llamar a Validate() antes de llamar a Save() o puede llamar a Save() directamente y Save() llamará a Validate() y probablemente lanzará una excepción si la validación falla.Práctica recomendada para devolver información adicional de una función Validar

Ahora, mi (principal) pregunta es esta;
Si mi función Validate() devuelve un bool simple, ¿cómo le digo al usuario de la clase qué es lo que está mal, es decir, "Correo electrónico no rellenado", "ID no único", etc. Para este propósito, solo quiero cadenas de error para pasar al usuario humano, pero el principio es el mismo si quiero una lista de códigos de error (excepto que hace que el uso de un mapa de bits sea más lógico).

  • Podría utilizar un parámetro de salida en mi función Validar pero entiendo que esto está mal visto.
  • En lugar de devolver un bool, podría devolver un conjunto de cadenas de mi función y simplemente probar si estaba vacío (es decir, sin errores), pero eso parece desordenado y no correcto.
  • Podría crear un Struct solo para regresar de este método, incluyendo un bool y una matriz de cadenas con mensajes de error, pero parece torpe.
  • Podría devolver un mapa de bits de códigos de error en lugar de un bool y buscarlo, pero parece bastante excesivo.
  • Podría crear una propiedad pública "ValidationErrors" en el objeto que contendría los errores. Sin embargo, eso dependería de que llame a Validate() antes de leerlo o llamar explícitamente a Validate desde la propiedad(), lo cual es un desperdicio de poco.

Mi programa específico está en C# pero parece una pregunta bastante genérica de "mejores prácticas" y estoy seguro de que debería saber la respuesta. Cualquier consejo recibido con gratitud.

Respuesta

5

Probablemente iré por la opción de mapa de bits.Simplemente

[Flags] 
public enum ValidationError { 
    None = 0, 
    SomeError = 1, 
    OtherError = 2, 
    ThirdError = 4 
} 

... y en el código de llamada, simplemente:

ValidationError errCode = employee.Validate(); 
if(errCode != ValidationError.None) { 
    // Do something 
} 

parece agradable y compacto para mí.

+0

+1 - Me ganaste. –

+0

Tiene razón, debería estar estructurado sobre mis mensajes de error y tener un repositorio central para ellos donde puedo buscarlos para la versión "amigable para el usuario", etc. – Frans

+0

El único truco que tengo con esta solución es que no lo haría use '0' como el valor de la primera enumeración decorada con' [Flag] '... – IAbstract

6

Pude crear un Struct solo para regresar de este método, incluyendo un bool y una matriz de cadenas con mensajes de error, pero parece torpe.

¿Por qué parece torpe? Crear un tipo apropiado para encapsular la información es perfecto. Sin embargo, no necesariamente usaría una cadena para codificar tal información. Una enumeración puede ser más adecuada.

Una alternativa sería subclasificar el tipo de devolución y proporcionar una clase secundaria adicional para cada caso, si es apropiado. Si se pueden señalar más de una falla, una matriz está bien. Pero encapsularía esto en un tipo propio también.

El patrón general podría tener este aspecto:

class ValidationInfo { 
    public bool Valid { get; private set; } 
    public IEnumerable<Failure> Failures { get; private set; } 
} 
1

que seguiría el patrón de los métodos TryParse y utilizar un método con esta firma:

public bool TryValidate(out IEnumerable<string> errors) { ... } 

Otra opción es tirar de la validación codifique el objeto en su propia clase, posiblemente basándose en el patrón de especificación.

public class EmployeeValidator 
{ 
    public bool IsSatisfiedBy(Employee candidate) 
    { 
     //validate and populate Errors 
    } 
    public IEnumerable<string> Errors { get; private set; } 
} 
0

Estamos utilizando la validación de primavera junto con un proveedor de errores de Windows Forms.

Por lo tanto, nuestra función de validación devuelve un diccionario con una identificación de control y un mensaje de error (por cada error de validación). El proveedor de errores muestra el mensaje de error en un campo emergente cerca del control que provocó el error.

He utilizado algunos otros esquemas de validación en el pasado, pero este funciona muy bien.

1

Me pareció un buen método simplemente tener un método (o una propiedad, ya que C# tiene un buen soporte para eso) que devuelve todos los mensajes de error de validación en algún tipo de formato sensato y fácil de usar, como una lista de cuerdas.

De esta manera también puede mantener su método de validación devolviendo bools.

2

Suena como que necesita una clase genérica:

public sealed class ValidationResult<T> 
{ 
    private readonly bool _valid; // could do an enum {Invalid, Warning, Valid} 
    private readonly T _result; 
    private readonly List<ValidationMessage> _messages; 

    public ValidationResult(T result) { _valid = true; _result = result; _messages = /* empty list */; } 

    public static ValidationResult<T> Error(IEnumerable<ValidationMessage> messages) 
    { 
     _valid = false; 
     _result = default(T); 
     _messages = messages.ToList(); 
    } 

    public bool IsValid { get { return _valid; } } 
    public T Result { get { if(!_valid) throw new InvalidOperationException(); return _result; } } 
    public IEnumerable<ValidationMessage> Messages { get { return _messages; } } // or ReadOnlyCollection<ValidationMessage> might be better return type 

    // desirable things: implicit conversion from T 
    // an overload for the Error factory method that takes params ValidationMessage[] 
    // whatever other goodies you want 
    // DataContract, Serializable attributes to make this go over the wire 
} 
+0

Me limitaría a añadir una referencia a lo que falló, si era la regla de nivel de atributo que faild luego referencia a esa propiedad, si era una entidad de ancho, luego referencia a la entidad, etc. – epitka

1

Se puede echar un vistazo a CSLA de Rockford Lhotka que tiene extensas reglas de negocio/rastreo de validación objetos de negocio forr en ella.

www.lhotka.net

1

Estoy de acuerdo con Chris W. Hice las mismas preguntas, antes de leer Rocky`s Experto C# objetos de negocio.

Tiene una manera brillante de manejar reglas de validación de negocios. La validación se realiza después de establecer cada propiedad. Cada vez que se rompe una regla, el estado del objeto se convierte en Invalid.

Su clase de negocios puede implementar la interfaz IDataError. Al vincular los controles de la interfaz de usuario a las propiedades de su objeto de negocio, se notificará a su control ErrorProvider de las reglas rotas en su objeto.

Realmente recomiendo que se tome el tiempo y mire la sección de validación.

Cuestiones relacionadas