1

I've been reviewing FluentValidation which is a nice validation library by the way but I noticed that they pass LambdaExpression in instead of an object property and I like to learn the advantage of this usage:

using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Company).NotNull();
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;

As you can see RuleFor(customer => customer.Surname).NotEmpty(); instead, RuleFor(customer.Surname).NotEmpty(); wouldn't be enough and clean?

2 Answers 2

6

instead, RuleFor(customer.Surname).NotEmpty(); wouldn't be enough and clean?

No. Because at the time when you're calling RuleFor, you don't have a customer - therefore you can't access their surname.

As is usually the case with delegates, you're passing around code to be executed at a later time. The expression customer.Surname is an expression which would be evaluated immediately in the context of an existing customer variable.

Now if we had the mythical infoof operator, we could do it without creating a delegate. We could potentially write something like:

RuleFor(infoof(Customer.Surname)).NotEmpty()

which would be lovely. The RuleFor method would take that property reference and evaluate it later against a given customer. Wonderful.

Unfortunately, we don't have that operator - so the easiest way of expressing the idea of "when you've got a customer, get hold of the Surname property" is to use a delegate. It's also very flexible, as it can work with (almost) any code you want to execute.

Sign up to request clarification or add additional context in comments.

6 Comments

I see it now. Thanks for the prompt answer! +1
I have one thing in my mind if you don't mind. What if there was a instance variable defined in the AbstractValidation<T> class such as T obj and when calling validate(customer), T obj could be set the customer instance and RuleFor(obj.Name) could be used.
Not really, because the whole point is to set up the validator once in the constructor, and have that apply to multiple instances over time. We want to call RuleFor once, not once per instance we validate.
But isn't that validating one instance at a time, I mean when saying Validate it gets the reference in order to validate its properties. Wouldn't be the same passing in "instance variable"? Since Validate will switch the reference address of the instance field.
@DorianGray: You call Validate, you pass in the value, sure - but that's not when the RuleFor code runs. The delegate that you pass into the RuleFor call runs during the Validate. That's the point. You're setting up code to run later on.
|
1

If you were to pass customer.SurName, you would be pointing to the value of the SurName property of a specific customer instance. Using a lambda function allows the validation logic to take a customer object when the validation logic is invoked, and then retrieve the SurName property of that customer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.