Esta é uma versão simplificada do problema original.
Eu tenho uma classe chamada Pessoa:
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
... e digamos uma instância:
var bob = new Person {
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = '1/1/2000'
}
Gostaria de escrever o seguinte como uma string no meu editor de texto favorito ....
(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3
Gostaria de pegar essa string e minha instância de objeto e avaliar um VERDADEIRO ou FALSO - ou seja, avaliar um Func <Pessoa, bool> na instância do objeto.
Aqui estão os meus pensamentos atuais:
- Implemente uma gramática básica no ANTLR para oferecer suporte a operadores lógicos e de comparação. Estou pensando em copiar a precedência do Visual Basic e alguns dos recursos aqui: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- Faça com que o ANTLR crie um AST adequado a partir de uma sequência fornecida.
- Caminhe pelo AST e use o Predicate Builder estrutura para criar dinamicamente o Func <Person, bool>
- Avalie o predicado em relação a uma instância de Person, conforme necessário
Minha pergunta é se eu cozinhei demais isso? alguma alternativa?
EDIT: Solução Escolhida
Decidi usar a biblioteca Dynamic Linq, especificamente a classe Dynamic Query fornecida nos LINQSamples.
Código abaixo:
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();
}
}
}
O resultado é do tipo System.Boolean e, neste caso, é VERDADEIRO.
Muito obrigado a Marc Gravell.
Inclua o pacote de nuget System.Linq.Dynamic , documentação aqui