#c# #properties #setter #getter
#c# #свойства #установщик #средство получения
Вопрос:
У меня есть пара переменных, которые я определяю в C # с помощью:
public String firstName { get; set; }
public String lastName { get; set; }
public String organization { get; set; }
Что я хочу, так это добавить проверку к этим методам при попытке установить значение. Допустим, вы собираетесь установить значение для FirstName, i должен пройти через регулярное выражение, чтобы оно действительно было установлено, в противном случае должно быть выдано исключение. Возможно ли это построить с помощью этого «короткого синтаксиса» или я должен использовать стандартные (например, в JAVA) средства получения и установки и там проверять данные?
Ответ №1:
Если вы хотите проверять, когда свойство установлено, вам необходимо использовать неавтоматические свойства (т. Е. определенные вручную get
и set
методы).
Но другой способ проверки — отделить логику проверки от объекта домена.
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
}
}
Тогда вы могли бы сказать:
Customer customer = // populate customer
var validator = new CustomerValidator();
if(!validator.Validate(customer)) {
// head splode
}
Это подход, который я предпочитаю:
- A
Customer
не должен отвечать за проверку своих собственных данных, это другая ответственность, и поэтому он должен находиться в другом месте. - В разных ситуациях требуется разная логика проверки для одного и того же объекта домена.
Комментарии:
1. Я не согласен, даже если ваша проверка завершается неудачей, данные вашего клиента недействительны. Что помешает ему записывать мусор в базу данных, если вы испортите внешнюю проверку?
2. @Blindy: Ваш уровень сохраняемости должен быть подключен к средствам проверки, которые не сохраняются, если проверка завершается неудачей.
3. Клиент @Blindy не должен нести ответственность за запись в базу данных. Это было бы еще одной ответственностью, которую клиент не должен нести.
4. Я понимаю «Принцип единой ответственности» (SRP), но мне всегда интересно, где должно быть «ограничение». Это означает, что вы могли бы зайти слишком далеко… например, создать класс для установки свойств (для вас). Я ничего не говорю о вашем примере… Кажется, я просто задаюсь вопросом: «Как далеко я должен зайти в применении SRP»? … может быть, я должен задать это как вопрос?
5. @Prisoner ZERO: Я думаю, что это хорошая основа для другого вопроса, но вам нужно будет привести конкретный пример, чтобы сделать его более определенным.
Ответ №2:
То, что у вас есть сейчас, называется «авто-свойства» и выполняет только простое «получение / установка». Чтобы настроить поведение get
или set
, вам нужно будет преобразовать свойства в свойства, поддерживаемые полями:
private string _firstName;
public string FirstName
{
get {return _firstName;}
set
{
Validate(value); _firstName = value;
}
}
Обратите внимание, что я изменил String
на string
и написал имя свойства с заглавной буквы, следуя принятым в C # рекомендациям по именованию.
Ответ №3:
Я бы вообще не добавлял проверку в setter
. Вместо этого я бы создал функцию, вызываемую validate
…таким образом, весь ваш код проверки находится в одном месте, а не разбросан по всему вашему setters
.
Ответ №4:
Наилучшей практикой является применение SRP. Установите проверку в отдельном классе.
Вы можете использовать FluentValidation
Install-Package FluentValidation
Вы бы определили набор правил проверки для класса Customer путем наследования от AbstractValidator<Customer>
:
Пример:
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
}
}
Чтобы запустить средство проверки, создайте экземпляр объекта validator и вызовите метод 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);
}
}
Комментарии:
1. Где появляется сообщение, полученное в результате проверки?
2. Сообщение может быть частью правила, например,
RuleFor(x => x.Forename).NotEmpty().WithMessage("Please specify a first name");
Ответ №5:
Для этого вы должны использовать полный синтаксис свойств.