C # lambda expressions or delegates as properties or arguments

I am looking to create a ValidationRule class that checks the properties of an entity object object. I would really like to set the name of the property being checked, and then give the class a delegate or lambda expression that will be evaluated at run time when the object runs its IsValid () method. Does anyone have a snippet of something similar or any ideas on how to pass an anonymous method as an argument or property?

Also, I'm not sure if I explain what I'm trying to accomplish, so ask questions if I don't understand.

+7
c # lambda
source share
5 answers

Indeed, you want to use Func<T,bool> , where T is the type of element you want to check. Then you will do something like this

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

you can save them in List<Func<T,bool>> .

+6
source share
 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); 

That should get you started. But, indeed, inheritance is much more appropriate here. The problem is simply that the Validator does not have access to any state that it does not close, which means that it is not as much as say ValidationRules , which contain their own state. Compare the following class with the previous textBoxHasText definition.

 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; } } } 
+3
source share

Well, just if you have an Entity class and you want to use lambda expressions for that Entity to determine if something is really (returning a boolean value), you can use Func.

So, given Entity:

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

You can define a ValidationRule class for this:

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

Then you can use it as follows:

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

Of course, this is only one possible solution.

If you remove the general restriction above ("where T: Entity"), you can make this a universal rule engine that can be used with any POCO. You would not need to derive a class for each type of use that you need. Therefore, if I wanted to use the same class in a TextBox, I could use the following (after removing the general constraint):

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

It is quite flexible. Using lambda expressions and generics together is very great. Instead of accepting Func or Action, you can accept Expression> or Expression> and have direct access to the heap expression to automatically examine things like the name of a method or property, type of expression, etc. And people using your class would not have to change one line of code.

+2
source share

something like:

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

there will be more C # 3 style, but will be compiled with the same code as @Frank Krueger. This is what you asked for, but don't feel good. Is there a good reason why an entity cannot be extended to perform validation?

+1
source share

Will rule-definition syntax like this work for you?

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

Consult DDD and Rule-Based Validated User Interface Validation in .NET for more information.

0
source share

All Articles