0

I want to create a generic validation class, so I can do something like:

Validation v = new Validation();
v.AddRequired(x => this.Name);
v.AddRange(x => x.this.Age, 5, 65);

I'm unsure as to how to write the method definition and make the evaluation?

Where AddRequired would take a string and AddRange would take a numeric type (int, primarily but also double, decimal, etc)

4

3 Answers 3

1

There should be some libraries available for this task. However, you can get some experience with lambdas by writing this yourself. I have made a draft implementation for the AddRange, I hope you can go further from here.

    public class Validation<T> {
        private List<RangeValidation> _rangeValidations = new List<RangeValidation>();

        public void AddRange(Func<T, int> func, int min, int max) {
            _rangeValidations.Add(new RangeValidation() {
                func = func,
                min = min,
                max = max
            });
        }

        public bool Validate(T obj) {
            foreach (var rangeValidation in _rangeValidations) {
                int value = rangeValidation.func(obj);
                if (value < rangeValidation.min || value > rangeValidation.max)
                    return false;
            }
            return true;
        }

        private class RangeValidation {
            public Func<T, int> func;
            public int min, max;
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

0

An approach would be:

class ObjectToBeValidated {
   public string Name { get; set; }
   public int Age { get; set; }
}

class Validation {
    private List<Expression<Func<ObjectToBeValidated, bool>>> requiredExpressions;
    private List<Expression<Func<ObjectToBeValidated, bool>>> rangeExpressions;

    public void AddRequired(Expression<Func<ObjectToBeValidated, string>> expression)
    {
        Expression<Func<ObjectToBeValidated, bool>> checkRequired = (p => !string.IsNullOrEmpty(expression.Compile().Invoke(p)));
        requiredExpressions.Add(checkRequired);
    }

    public void AddRange(Expression<Func<ObjectToBeValidated, int>> expression, int min, int max)
    {
        Func<ObjectToBeValidated, int> compiledFunc = expression.Compile();
        Expression<Func<ObjectToBeValidated, bool>> checkRange = (p => compiledFunc.Invoke(p) >= min && compiledFunc.Invoke(p) < max);
        rangeExpressions.Add(checkRange);
    }
}

This would just store your conditions in List<T>'s. You then would have to add a method to your Validation class to evaluate the expressions:

public bool IsValid(ObjectToBeValidated testObject)
    {
        return requiredExpressions.All(p => p.Compile().Invoke(testObject))
            && rangeExpressions.All(p => p.Compile().Invoke(testObject));
    }

Then use like this:

validator.AddRequired(p => p.Name);
validator.AddRange(p => p.Age, 6, 15);

var myObject = new ObjectToBeValidated();
var result = validator.IsValid(myObject);

1 Comment

Of course, you could also compile the expressions in the AddRequired and AddRange methods already, add them to a List<Func<ObjectToBeValidated, bool>>, and just invoke them in the IsValid function. Also, you could use one List of those for all conditions instead one for each condition type like in my example.
0

Make Validation generic on the type of x, define methods taking Func<x,object> or some other type as needed, store these functions, and call them from the Validate(x) method:

class Validation<T> {
    private IList<Tuple<Func<T,IComparable>,IComparable,IComparable>> rangeChecks = new List<Tuple<Func<T,IComparable>,IComparable,IComparable>>();
    private IList<Func<T,object>> nullChecks = new List<Func<T,object>>;
    public AddRequired(Func<T,object> f) {
        nullChecks.Add(f);
    }
    public AddRange(Func<T,IComparable> f, IComparable low, IComparable high) {
        rangeChecks.Add(Tuple.Create(f, low, high));
    }
    public bool Validate(T x) {
        foreach(var t in rangeChecks) {
            var f = t.Item1;
            var low = t.Item2;
            var high = t.Item3;
            var val = f(x);
            if (v.CompareTo(low) < 0 || v.CompareTo(high) > 0) {
                return false;
            }
        }
        foreach (var t in nullChecks) {
            if (t(x) == null) {
                return false;
            }
        }
        return true;
    }
}

This implementation is very skeletal - it needs null checks in many places to be useful. In addition, it's not very efficient, because IComparable and object could wrap value types. However, the way of passing and storing Func<T,...> objects should give you an idea of how to implement the rest of it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.