Выражение Func и действие, как передать значение функции func в действие - PullRequest
3 голосов
/ 15 апреля 2019

У меня есть класс, который имеет 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)), что было бы некорректно и с ошибкой во время выполнения.

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

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

1 Ответ

2 голосов
/ 15 апреля 2019

Вместо 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));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...