I have a db table that stores the following:
RuleID objectProperty ComparisonOperator TargetValue
1 age 'greater_than' 15
2 username 'equal' 'some_name'
3 tags 'hasAtLeastOne' 'some_tag some_tag2'
Now say I have a collection of these rules:
List<Rule> rules = db.GetRules();
Now I have an instance of a user also:
User user = db.GetUser(....);
How would I loop through these rules, and apply the logic and perform the comparisons etc?
if(user.age > 15)
if(user.username == "some_name")
Since the object's property like 'age' or 'user_name' is stored in the table, along with the comparison operater 'great_than' and 'equal', how could I possible do this?
C# is a statically typed language, so not sure how to go forward.
Best Answer
This snippet compiles the Rules into fast executable code (using Expression trees) and does not need any complicated switch statements:
(Edit : full working example with generic method)
You can then write:
Here is the implementation of BuildExpr:
Note that I used 'GreaterThan' instead of 'greater_than' etc. - this is because 'GreaterThan' is the .NET name for the operator, therefore we don't need any extra mapping.
If you need custom names you can build a very simple dictionary and just translate all operators before compiling the rules:
The code uses the type User for simplicity. You can replace User with a generic type T to have a generic Rule compiler for any types of objects. Also, the code should handle errors, like unknown operator name.
Note that generating code on the fly was possible even before the Expression trees API was introduced, using Reflection.Emit. The method LambdaExpression.Compile() uses Reflection.Emit under the covers (you can see this using ILSpy).