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?
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.Surnameis an expression which would be evaluated immediately in the context of an existingcustomervariable.Now if we had the mythical infoof operator, we could do it without creating a delegate. We could potentially write something like:
which would be lovely. The
RuleFormethod 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
Surnameproperty” is to use a delegate. It’s also very flexible, as it can work with (almost) any code you want to execute.