This is a simplified version of the original problem.
I have a class called Person:
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
...and lets say an instance:
var bob = new Person {
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = '1/1/2000'
}
I would like to write the following as a string in my favourite text editor....
(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3
I would like to take this string and my object instance and evaluate a TRUE or FALSE - i.e. evaluating a Func<Person, bool> on the object instance.
Here are my current thoughts:
- Implement a basic grammar in ANTLR to support basic Comparison and Logical Operators. I am thinking of copying the Visual Basic precedence and some of the featureset here: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- Have ANTLR create a suitable AST from a provided string.
- Walk the AST and use the Predicate Builder framework to dynamically create the Func<Person, bool>
- Evaluate the predicate against an instance of Person as required
My question is have I totally overbaked this? any alternatives?
EDIT: Chosen Solution
I decided to use the Dynamic Linq Library, specifically the Dynamic Query class provided in the LINQSamples.
Code below:
using System;
using System.Linq.Expressions;
using System.Linq.Dynamic;
namespace ExpressionParser
{
class Program
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
static void Main()
{
const string exp = @"(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3";
var p = Expression.Parameter(typeof(Person), "Person");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, exp);
var bob = new Person
{
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = new DateTime(2000,1,1)
};
var result = e.Compile().DynamicInvoke(bob);
Console.WriteLine(result);
Console.ReadKey();
}
}
}
Result is of type System.Boolean, and in this instance is TRUE.
Many thanks to Marc Gravell.
Include System.Linq.Dynamic nuget package, documentation here
CSharpSamples\LinqSamples\DynamicQuery\DynamicQuery
and then either 1) copy thedynamic.cs
class from the sample project into your project or 2) putdynamic.cs
into it's own project as a seperate dll with filename and default namespace ofSystem.Linq.Dynamic
(which is what I did because it's more DRY. – Aldis