2008-09-26 27 views
7

Estoy buscando crear una clase ValidationRule que valide propiedades en un objeto de tipo de entidad. Realmente me gustaría establecer el nombre de la propiedad para inspeccionar y luego darle a la clase un delegado o una expresión lambda que se evaluará en tiempo de ejecución cuando el objeto ejecute su método IsValid(). ¿Alguien tiene un fragmento de algo como esto, o alguna idea sobre cómo pasar un método anónimo como argumento o propiedad?C# Lambda Expresiones o delegados como propiedades o argumentos

Además, no estoy seguro si estoy explicando lo que estoy tratando de lograr así que por favor haga preguntas si no estoy siendo claro.

Respuesta

3
class ValidationRule { 
    public delegate bool Validator(); 

    private Validator _v; 

    public ValidationRule(Validator v) { _v = v; } 

    public Validator Validator { 
     get { return _v; } 
     set { _v = value; } 
    } 

    public bool IsValid { get { return _v(); } } 
} 

var alwaysPasses = new ValidationRule(() => true); 
var alwaysFails = new ValidationRule(() => false); 

var textBoxHasText = new ValidationRule(() => textBox1.Text.Length > 0); 

Eso debería comenzar. Pero, realmente, la herencia es mucho más apropiada aquí. El problema es simplemente que el Validator no tiene acceso a ningún estado que no se cierre, esto significa que no es tan reutilizable como dice ValidationRules que contiene su propio estado. Compare la siguiente clase con la definición anterior de textBoxHasText.

interface IValidationRule { 
    bool IsValid { get; } 
} 

class BoxHasText : IValidationRule { 
    TextBox _c; 

    public BoxHasText(TextBox c) { _c = c; } 

    public bool IsValid { 
     get { return _c.Text.Length > 0; } 
    } 
} 
+0

¿Puede ampliar el punto de herencia? –

6

En realidad, lo que desea utilizar es Func<T,bool> donde T es el tipo de elemento que desea validar. De allí tendría que hacer algo como esto

validator.AddValidation(item => (item.HasEnoughInformation() || item.IsEmpty()); 

se podría almacenar en un List<Func<T,bool>>.

+0

Creo que usar Predicate podría ser un poco más que Func

+0

Ah sí, el predicado es genial, básicamente lo mismo. –

1

algo como:

class ValidationRule 
{ 
    private Func<bool> validation; 

    public ValidationRule(Func<bool> validation) 
    { 
     this.validation = validation; 
    } 
    public bool IsValid() 
    { 
     return validation(); 
    } 
} 

habría más al estilo de C# 3, pero se compila para el mismo código que la respuesta de @Frank Krueger. Esto es lo que pidió, pero no se siente bien. ¿Hay una buena razón por la cual la entidad no puede extenderse para realizar la validación?

2

Bueno, simplemente, si tiene una clase de Entidad, y quiere usar expresiones lambda en esa Entidad para determinar si algo es válido (devolviendo booleano), podría usar un Func.

Por lo tanto, dado que la entidad:

class Entity 
{ 
     public string MyProperty { get; set; } 
} 

se podría definir una clase ReglaDeValidación para que de esta manera:

class ValidationRule<T> where T : Entity 
{ 
     private Func<T, bool> _rule; 

     public ValidationRule(Func<T, bool> rule) 
     { 
      _rule = rule; 
     } 

     public bool IsValid(T entity) 
     { 
      return _rule(entity); 
     } 
} 

entonces se podría utilizar de esta manera:

var myEntity = new Entity() { MyProperty = "Hello World" }; 
var rule = new ValidationRule<Entity>(entity => entity.MyProperty == "Hello World"); 

var valid = rule.IsValid(myEntity); 

Por supuesto, esa es solo una posible solución.

Si elimina la restricción genérica anterior ("donde T: Entidad"), puede hacer que este sea un motor de reglas genéricas que podría usarse con cualquier POCO. No tendrías que derivar una clase para cada tipo de uso que necesites. Así que si quería utilizar esta misma clase en un cuadro de texto, podría usar el siguiente (después de la eliminación de la restricción genérica):

var rule = new ValidationRule<TextBox>(tb => tb.Text.Length > 0); 
rule.IsValid(myTextBox); 

es bastante flexible, de esta manera. Usar expresiones lambda y genéricos juntos es muy poderoso. En lugar de aceptar Func o Action, puede aceptar Expression> o Expression> y tener acceso directo al árbol express para investigar automáticamente cosas como el nombre de un método o propiedad, qué tipo de expresión es, etc. Y las personas que usan su la clase no tendría que cambiar una sola línea de código.

0

¿Sería útil para usted una sintaxis de definición de reglas como esta?

public static void Valid(Address address, IScope scope) 
    { 
    scope.Validate(() => address.Street1, StringIs.Limited(10, 256)); 
    scope.Validate(() => address.Street2, StringIs.Limited(256)); 
    scope.Validate(() => address.Country, Is.NotDefault); 
    scope.Validate(() => address.Zip, StringIs.Limited(10)); 

    switch (address.Country) 
    { 
     case Country.USA: 
     scope.Validate(() => address.Zip, StringIs.Limited(5, 10)); 
     break; 
     case Country.France: 
     break; 
     case Country.Russia: 
     scope.Validate(() => address.Zip, StringIs.Limited(6, 6)); 
     break; 
     default: 
     scope.Validate(() => address.Zip, StringIs.Limited(1, 64)); 
     break; 
    } 

Salida DDD and Rule driven UI Validation in .NET para más información

Cuestiones relacionadas