-
-
Save NDiiong/9349cfb512110becf29df1f424f43c2d to your computer and use it in GitHub Desktop.
Simple Generic Object Validation as based on solution found here: https://codereview.stackexchange.com/questions/178106/simple-object-validator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Linq.Expressions; | |
// I loved this when I found here: https://codereview.stackexchange.com/questions/178106/simple-object-validator | |
namespace Tools.Validate.Objects // could be something else | |
{ | |
public class Validation | |
{ | |
public bool Success { get; } | |
public string Message { get; } | |
public Validation(bool success, string message) | |
{ | |
Success = success; | |
Message = message; | |
} | |
} | |
public class ValidationRule<T> | |
{ | |
private readonly string _expression; | |
private readonly Func<T, bool> _predicate; | |
public ValidationRule(string expression, Func<T, bool> predicate) | |
{ | |
_expression = expression; | |
_predicate = predicate; | |
} | |
public bool IsMet(T obj) => _predicate(obj); | |
public override string ToString() => _expression; | |
} | |
public class Validator<T> | |
{ | |
const string SUCCESS_VERB = "Object of type {0} Failed: {1}"; | |
const string FAILURE_VERB = "Object of type {0} Succeded: {1}"; | |
private readonly IEnumerable<ValidationRule<T>> _rules; | |
public Validator(IEnumerable<ValidationRule<T>> rules) | |
{ | |
_rules = rules; | |
} | |
public static ValidatorBuilder<T> Builder => new ValidatorBuilder<T>(); | |
public bool IsValid(T obj) | |
{ | |
return _rules.All(r => r.IsMet(obj)); | |
} | |
public IEnumerable<Validation> Validate(T obj) | |
{ | |
if(obj == null) | |
{ | |
yield return new Valdiation(false, string.Format( | |
FAILURE_VERB, | |
typeof(T).Name, | |
"Is not null")); | |
yield break; | |
} | |
foreach(var rule in _rules) | |
{ | |
var isValid = rule.IsMet(obj); | |
yield return new Validation(isValid, isValid | |
? string.Format(SUCCESS_VERB, typeof(T).Name, rule) | |
: string.Format(FAILURE_VERB, typeof(T).Name, rule)); | |
} | |
} | |
} | |
public class ReplaceVisitor : ExpressionVisitor | |
{ | |
private Expression _from, _to; | |
public ReplaceVisitor(Expression from, Expression to) | |
{ | |
_from = from; | |
_to = to; | |
} | |
protected override Expression VisitParameter(ParameterExpression node) | |
{ | |
return node.Equals(_from) ? _to : base.VisitParameter(node); | |
} | |
public static Expression Replace(Expression target, Expression from, Expression to) | |
{ | |
return new ReplaceVisitor(from, to).Visit(target); | |
} | |
} | |
public class ValidationBuilder<T> | |
{ | |
private readonly List<ValidationRule<T>> _rules = new List<ValidationRule<T>>(); | |
public ValidationBuilder<T> Where(Expression<Func<T,bool>> expression) | |
{ | |
var typeParameter = Expression.Parameter(typeof(T), typeof(T).Name); | |
var expressionString = ReplaceVisitor.Replace( | |
expression.Body, | |
expression.Parameters[0], | |
typeParameter) | |
.ToString(); | |
_rules.Add(new ValidationRule<T>(expressionString, expression.Compile())); | |
return this; | |
} | |
public Validator<T> Build() | |
{ | |
return new Validator<T>(_rules); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment