Выражение Func и действие, как передать значение функции func в действие

2

У меня есть класс, который имеет 2 метода:

MaxLength(string text, int maxLength, string propName, string message = null); MinValue(int value, int min, string propName, string message = null);

Как пользователь может потреблять его, передавая каждое из значений. Я хочу сделать это проще и более похожим на autopper, когда они хотят проверить класс. такие как

public class MyModel {
   public string Category { get; set; }
   public int Number { get; set; }
}

на данный момент им придется написать

MyModel model = //comes from API call or where ever
var validator = new Validator();
validator.MaxLength(model.Category, 4, "Category");
validator.MinValue(model.Number , 3, "Number ");

то, чего я хочу достичь, это возможность настроить сопоставления для класса:

public class Profile1 : ClassValidationProfile
{
    public Profile1()
    {
        CreateMap<Model1>()
            .ForMember(x => x.Category, m => m.MaxLength(4))
            .ForMember(x => x.Number , m => m.MinValue(3));
    }
}

Итак, на основе автопереключателя у меня есть:

IMappingExpression<T> ForMember<TMember>(Expression<Func<T, TMember>> member, Action<IValidatorExpression> memberAction)

но это позволило бы мне установить .ForMember(x => x.Name, m => m.MinValue(18)) который был бы неправильным и с ошибкой во время выполнения.

Я хотел бы иметь возможность ограничить Action memberAction их правильным типом (строки против строки, целые числа для целых и т.д.). Поэтому, когда пользователь настраивает свои сопоставления, он знает, какие методы действия допустимы для типа свойства, которое они дали в первой части выражения.

Затем он может использовать эту информацию, чтобы иметь возможность генерировать допустимые методы проверки для каждого из свойств.

Теги:
expression

1 ответ

0

Вместо Action<IValidatorExpression> вы должны использовать что-то с TMember для сохранения типа - например, Func<TMember, bool> (функция, которая принимает значение элемента в качестве входных данных и возвращает логическое значение, указывающее, прошла или нет валидация).

Я попытался создать небольшой пример программы, где окончательная проверка выглядит следующим образом:

var validator = Validator<MyModel>.Create()
    .ForMember(x => x.Category, cat => cat == "A")
    .ForMember(x => x.Number, num => num < 200);

MyModel model = new MyModel {
    Category = "A",
    Number = 100,
};

validator.Validate(model);

Это то, что ты искал?

Вот код для достижения вышеуказанного:

class Validator<TClass> {
    private List<IObjectValidator<TClass>> _constraints = new List<IObjectValidator<TClass>>();

    public static Validator<TClass> Create() {
        return new Validator<TClass>();
    }

    public Validator<TClass> ForMember<TMember>(Expression<Func<TClass, TMember>> memberSelectorExpression, Func<TMember, bool> memberValidation, string errorMessage = null) {
        _constraints.Add(new ObjectValidator<TClass, TMember>(memberSelectorExpression.Compile(), memberValidation, errorMessage ?? memberSelectorExpression.ToString() + " did not pass validation"));
        return this;
    }

    public void Validate(TClass obj) {
        foreach (var constraint in _constraints) {
            if (!constraint.Validate(obj))
                throw new Exception(constraint.ErrorMessage);
        }
    }
}

interface IObjectValidator<T> {
    bool Validate(T obj);
    string ErrorMessage { get; }
}

class ObjectValidator<T, TMember> : IObjectValidator<T>
{
    private Func<T, TMember> _memberSelector;
    private Func<TMember, bool> _memberValidation;
    public string ErrorMessage { get; }


    public ObjectValidator(Func<T, TMember> memberSelector, Func<TMember, bool> memberValidation, string errorMessage) {
        _memberSelector = memberSelector;
        _memberValidation = memberValidation;
        ErrorMessage = errorMessage;
    }

    public bool Validate(T obj)
    {
        return _memberValidation.Invoke(_memberSelector.Invoke(obj));
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню