Как использовать определенный объект вместо строки в C #?

#c# #.net #refactoring #dry #fluentvalidation

#c# #.net #рефакторинг #dry #плавная проверка

Вопрос:

У меня есть несколько классов моделей, и я заметил, что Name свойство (например: название страны, имя_ ветви, имя_статьи и т.д.) Имеет одинаковое правило во всем приложении, например, оно должно быть обязательным и не может превышать определенного количества символов. В следующем примере BranchAddClass.cs .


Вопрос:


  1. Как определить пользовательский объект и повторно использовать в Model Class коде вместо объявления в виде строки (см. BranchName Свойство в BranchAddModel.cs ).
  2. Как реализовать FluentValidation правила в файле nameField.cs. На данный момент проверка повторяется (см. BranchAddModel.cs Класс).

nameField.cs

Я думал создать класс object и выполнить проверку в этом классе, чтобы не нарушать DRY принцип. Но я не могу этого достичь. Если у вас есть лучший способ реализовать то, чего я пытаюсь достичь, я бы приветствовал!

 public class NameField
    {
        private readonly string _value;

        private NameField(string value)
        {
            _value = value;
        }
    }
  

Если класс nameField работает, то я надеюсь, что смогу использовать его в остальной части приложения, см. Пример

BranchAddModel.cs

 namespace Application
{
    [Validator(typeof(BranchAddModelValidator))]
    public class BranchAddModel
    {
        public byte ServiceTypeId { get; set; }
        public string BranchName { get; set; }  //this could be replaced when NameField issue is solved.
        public NameField PreferredBranchName { get; set; }   //Reference to NameField class
        public short BaseCurrencyId { get; set; }
        public short TimezoneId { get; set; }
    }

    public class BranchAddModelValidator : AbstractValidator<BranchAddModel>
    {
        public BranchAddModelValidator()
        {
            //trying to avoid writing this validation.
            RuleFor(x => x.BranchName)
                .NotEmpty()
                .Length(0, 128);

            RuleFor(x => x.ServiceTypeId)
                .NotEmpty();

            RuleFor(x => x.BaseCurrencyId)
                .NotEmpty();

            RuleFor(x => x.TimezoneId)
                .NotEmpty();
        }
    }
}
  

Примечание: Если вы считаете, что вопрос неясен, пожалуйста, дайте мне знать.

Комментарии:

1. Используйте отражение для построения дерева выражений для передачи в RuleFor

2. @Rob Не могли бы вы, пожалуйста, привести пример?

Ответ №1:

Я бы попробовал использовать дженерики. Таким образом, вы можете легко добавить его в другие модели и свойства (countryName, StateName).

 public class BranchAddModelValidator : AbstractValidator<BranchAddModel>
{
    public BranchAddModelValidator()
    {
        this.AddDefaultNameValidation(x => x.BranchName);

        RuleFor(x => x.ServiceTypeId)
            .NotEmpty();

        RuleFor(x => x.BaseCurrencyId)
            .NotEmpty();

        RuleFor(x => x.TimezoneId)
            .NotEmpty();
    }
}

public static class AbstractValidatorExtensions
{
    public static void AddDefaultNameValidation<T>(this AbstractValidator<T> validator, Expression<Func<T, string>> property)
    {
        validator.RuleFor(property)
            .NotEmpty()
            .Length(0, 128);
    }
}
  

ПРИМЕЧАНИЕ: Он компилируется, но я не проверял, работает ли проверка на самом деле. Пакет Fluent Validation для меня новый, и сейчас у меня нет времени его изучать, но, похоже, стоит запомнить.

Ответ №2:

Вместо того, чтобы оборачивать класс, вы можете сделать что-то вроде этого:

 var param = Expression.Parameter(typeof(BranchAddModel));
var items = typeof(BranchAddModel).GetProperties()
    .Where(p => p.PropertyType == typeof(string))
    .Select(r => Expression.Lambda<Func<BranchAddModel, string>>(Expression.PropertyOrField(param, r.Name), param));

foreach (var item in items)
{
    RuleFor(item)
        .NotEmpty()
        .Length(0, 128);
}
  

Который создаст перечислимый из Expression<Func<BranchAddModel, string>> , который вы можете затем перебирать и передавать в RuleFor