Это упрощенная версия оригинальной задачи.
У меня есть класс под названием Person:
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
... и давайте скажем экземпляр:
var bob = new Person {
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = '1/1/2000'
}
Я хотел бы написать следующее в виде строки в моем любимом текстовом редакторе ....
(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3
Я хотел бы взять эту строку и мой экземпляр объекта и оценить ИСТИНА или ЛОЖЬ - то есть вычисление Func <Person, bool> на экземпляре объекта.
Вот мои нынешние мысли:
- Реализовать базовую грамматику в ANTLR для поддержки базовых сравнений и логических операторов. Я думаю о копировании приоритета Visual Basic и некоторых из набора функций здесь: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- Пусть ANTLR создаст подходящий AST из предоставленной строки.
- Пройдите AST и используйте Построителя Предикатов инфраструктуру для динамического создания Func <Person, bool>
- Оцените предикат против экземпляра Person по мере необходимости
Мой вопрос: я полностью переварила это? какие-нибудь альтернативы?
РЕДАКТИРОВАТЬ: Выбранное решение
Я решил использовать Dynamic Linq Library, в частности класс Dynamic Query, предоставленный в LINQSamples.
Код ниже:
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();
}
}
}
Результат имеет тип System.Boolean, и в этом случае TRUE.
Большое спасибо Марку Гравеллу.
Включите пакет nuget System.Linq.Dynamic , документацию здесь
Ответы:
Поможет ли здесь динамическая библиотека linq ? В частности, я думаю, как
Where
оговорка. Если необходимо, поместите его в список / массив, чтобы вызвать.Where(string)
его! т.е.Если нет, то написание парсера (использующего
Expression
под капотом) не очень обременительно - я написал один подобный (хотя я не думаю, что у меня есть источник) в моем поезде, перед самым рождеством ...источник
// Lambda expression as data in the form of an expression tree.
System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
// Compile the expression tree into executable code.
Func<int, bool> deleg = expr.Compile();
// Invoke the method and print the output.
Console.WriteLine("deleg(4) = {0}", deleg(4));
ParseLambda хорошо!Еще одна такая библиотека - это Flee
Я сделал быстрое сравнение Dynamic Linq Library и Flee и Flee было в 10 раз быстрее для выражения
"(Name == \"Johan\" AND Salary > 500) OR (Name != \"Johan\" AND Salary > 300)"
Вот как вы можете написать свой код, используя Flee.
источник
У LinqPad есть
Dump()
методисточник
var type = typeof(T); var prop = type.GetProperty(propName);
чтобы заставить его скомпилировать.Вы могли бы взглянуть на DLR . Это позволяет вам оценивать и выполнять скрипты внутри приложения .NET 2.0. Вот пример с IronRuby :
Конечно, этот метод основан на оценке во время выполнения, и код не может быть проверен во время компиляции.
источник
Вот пример Scala DSL-комбинатора синтаксического анализа для анализа и вычисления арифметических выражений.
Дерево эквивалентного выражения или дерево разбора предоставленного арифметического выражения будет иметь тип Parser [List [String]].
Более подробная информация находится по следующей ссылке:
http://nicolaecaralicea.blogspot.ca/2013/04/scala-dsl-for-parsing-and-evaluating-of.html
источник
В дополнение к динамической библиотеке Linq (которая создает строго типизированное выражение и требует строго типизированных переменных), я рекомендую лучшую альтернативу: синтаксический анализатор linq той части библиотеки NReco Commons (с открытым исходным кодом). Он выравнивает все типы и выполняет все вызовы во время выполнения и ведет себя как динамический язык:
источник
Хотя это относительно старая статья - это код для построителя выражений: AnyService - ExpressionTreeBuilder Это модульные тесты: AnyService - ExpressionTreeBuilder Модульные тесты
источник