I have a a couple of variables that i define in C# by:
publi开发者_StackOverflow中文版c String firstName { get; set; }
public String lastName { get; set; }
public String organization { get; set; }
What i want is to add validation to these methods when you try to set a value. Lets say your going to set a value for firstName, the i should pass thrue a regexp to actuelly be set, otherwise an exception should be thrown. Is this possible to build with this "short syntax" or should I go for standard (like in JAVA) getters and setters and in there validate the data?
If you want to validate when the property is set, you need to use non-auto properties (i.e., manually defined get
and set
methods).
But another way to validate is to have the validation logic separate from the domain object.
class Customer {
public string FirstName { get; set; }
public string LastName { get; set; }
public string Organization { get; set; }
}
interface IValidator<T> {
bool Validate(T t);
}
class CustomerValidator : IValidator<Customer> {
public bool Validate(Customer t) {
// validation logic
}
}
Then, you could say:
Customer customer = // populate customer
var validator = new CustomerValidator();
if(!validator.Validate(customer)) {
// head splode
}
This is the approach I prefer:
- A
Customer
should not responsible for validating its own data, that is another responsibility and therefore should live elsewhere. - Different situations call for different validation logic for the same domain object.
What you have now are called "auto-properties," and only perform a simple "get/set". In order to customize the behavior of the get
or set
, you will need to convert the properties to field-backed properties:
private string _firstName;
public string FirstName
{
get {return _firstName;}
set
{
Validate(value); _firstName = value;
}
}
Note that I changed String
to string
and capitalized the property name, in following accepted C# naming best practices.
I wouldn't add validation in the setter
at all. Rather, I would create a function called validate
instead...that way all your validation code is in one spot rather scattered throughout your setters
.
It's best practice to apply SRP. Set the validation in a separate class.
You can use FluentValidation
Install-Package FluentValidation
You would define a set of validation rules for Customer class by inheriting from AbstractValidator<Customer>
:
Example:
public class CustomerValidator : AbstractValidator<Customer> {
public CustomerValidator() {
RuleFor(x => x.Surname).NotEmpty();
RuleFor(x => x.Forename).NotEmpty().WithMessage("Please specify a first name");
RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount);
RuleFor(x => x.Address).Length(20, 250);
RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
}
private bool BeAValidPostcode(string postcode) {
// custom postcode validating logic goes here
}
}
To run the validator, instantiate the validator object and call the Validate method, passing in the object to validate.
Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult result = validator.Validate(customer);
if(! results.IsValid) {
foreach(var failure in results.Errors) {
Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
} }
You have to use the full property syntax for this.
精彩评论