Il s'agit d'une version simplifiée du problème d'origine.
J'ai une classe appelée Person:
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
... et disons une instance:
var bob = new Person {
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = '1/1/2000'
}
Je voudrais écrire ce qui suit sous forme de chaîne dans mon éditeur de texte préféré ...
(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3
Je voudrais prendre cette chaîne et mon instance d'objet et évaluer un TRUE ou FALSE - c'est-à-dire évaluer un Func <Person, bool> sur l'instance d'objet.
Voici mes pensées actuelles:
- Implémentez une grammaire de base dans ANTLR pour prendre en charge la comparaison de base et les opérateurs logiques. Je pense à copier la priorité Visual Basic et certaines fonctionnalités ici: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- Demandez à ANTLR de créer un AST approprié à partir d'une chaîne fournie.
- Parcourez l'AST et utilisez le framework Predicate Builder pour créer dynamiquement le Func <Person, bool>
- Évaluez le prédicat par rapport à une instance de Person comme requis
Ma question est: ai-je totalement surchargé cela? des alternatives?
EDIT: Solution choisie
J'ai décidé d'utiliser la bibliothèque Dynamic Linq, en particulier la classe Dynamic Query fournie dans LINQSamples.
Code ci-dessous:
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();
}
}
}
Le résultat est de type System.Boolean, et dans ce cas est TRUE.
Un grand merci à Marc Gravell.
Inclure le package nuget System.Linq.Dynamic, documentation ici