Per la progettazione di un database, tutto ciò che serve è sinistra, operatore e destra.
Qualcosa del genere:
X > 10
Una tabella come questa:
RuleSetID PropertyName Operand TargetValue
1 Weight LessThan 200
Quindi puoi usare System.Linq.Expressions
namespace per creare dinamicamente espressioni per la valutazione.
Per ulteriori informazioni su questa funzione di framework .Net, visita questo link:
link
Sono supportati tutti i tipi di operatori, maggiori di, minori di ecc.
Ora, un po 'di codice per compilare le espressioni:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using RulesEngine.Model;
using System.Diagnostics;
namespace RulesEngine.Engine
{
public class ExpressionBuilder
{
public Func<T, bool> Compile<T>(Rule rule, Type type)
{
try
{
var param = Expression.Parameter(type);
Expression expression = BuildExpression<T>(rule, param);
return Expression.Lambda<Func<T, bool>>(expression, param).Compile();
}
catch (Exception exception)
{
//We would want to log this failure so the rule can be corrected.
Debug.WriteLine(exception.ToString());
//Return an expresssion that would always return false
Expression<Func<T, bool>> defaultLambda = x => false;
return defaultLambda.Compile();
}
}
private Expression BuildExpression<T>(Rule rule, ParameterExpression param)
{
var left = MemberExpression.Property(param, rule.PropertyName);
var propertyType = typeof(T).GetProperty(rule.PropertyName).PropertyType;
ExpressionType binaryExpressionType;
if (ExpressionType.TryParse(rule.Operand, out binaryExpressionType))
{
var right = Expression.Constant(Convert.ChangeType(rule.TargetValue, propertyType));
return Expression.MakeBinary(binaryExpressionType, left, right);
}
else
{
var methodName = propertyType.GetMethod(rule.Operand);
var parameterType = methodName.GetParameters()[0].ParameterType;
var right = Expression.Constant(Convert.ChangeType(rule.TargetValue, parameterType));
return Expression.Call(left, methodName, right);
}
}
}
}
Una regola sarebbe una classe per contenere la definizione dal database.
using System;
using System.Collections.Generic;
using System.Linq;
namespace RulesEngine.Model
{
public class Rule
{
public string PropertyName { get; private set; }
public string Operand { get; private set; }
public string TargetValue { get; private set; }
public Rule(string propertyName, string operand, string targetValue)
{
PropertyName = propertyName;
Operand = operand;
TargetValue = targetValue;
}
}
}
Ora creiamo un oggetto per contenere i dati dell'istanza. (Sostituisci foo con i dati della tua istanza di soglia).
public class Foo
{
public string Name { get; private set; }
public int Weight { get; private set; }
public int Size { get; private set; }
public Foo(string name, int weight, int size)
{
Name = name;
Weight = weight;
Size = size;
}
}
E infine mettendo tutto insieme ... confrontando i dati dell'istanza con la regola.
private static void RunExample()
{
var rule = new Rule("Weight","Equal", "100");
var foo = new Foo("FooName", 100, 200);
var expressionBuilder = new ExpressionBuilder();
Func<Foo, bool> fooRule = expressionBuilder.Compile<Foo>(rule, foo.GetType());
Console.WriteLine("Is weight equal to 100 for foo?" + fooRule(foo)); //true
}
Dal momento che è generico, puoi utilizzarlo come un mini motore di regole che può prendere qualsiasi dato di istanza e confrontarlo con un insieme di regole per restituire vero / falso.