Разбор условных выражений в строку

Я ищу способ синтаксического анализа условного выражения в строку.

Лучший пример, который я могу придумать, это LINQ-to-SQL. Он использует ExpressionVisitors для форматирования предложений «Где». Пример:

from a in b where a.x == 5 && a.y < 3 select a

Это будет переводиться в следующую строку (примерно, MSSQL для меня не актуален):

"SELECT * FROM b WHERE x = 5 AND y < 3"

Из того, что я читал, это было сделано с помощью класса ExpressionVisitor, как описано в этой статье: http://blogs.msdn.com/b/mattwar/archive/2007/07/31/linq-build-an-queryable-provider-part-ii.aspx

Теперь проблема в том, что я не использую LINQ, но мне нужен именно этот функционал. Есть ли способ разобрать такое состояние? Я готов делать что угодно с отражением, делегатами, лямбдой и т.д.

Честно говоря, я не думаю, что это возможно, но мои мозги немного поджарены (читай: будьте любезны, если вопрос смешной), так что я решил, что с тем же успехом мог бы попробовать S/O .

EDIT: окончательный пример использования:

// Usage:
foo.Bar(foo => foo.X == 5 && foo.Y < 3)

// Ideal string output (variable name (foo) is not needed):
"foo.X == 5 && foo.Y < 3"

РЕДАКТИРОВАТЬ 2: Да, число может быть меньше 3 и равно 5. Говорил же вам, что мой мозг поджарился.


person Lazlo    schedule 17.11.2010    source источник
comment
LINQ-to-SQL делает именно это. Если вы напишите свой собственный, вы будете заново реализовывать LINQ-to-SQL, который уже существует — это кажется бессмысленным усилием. (Тем не менее, люди это сделали; например, поищите в Google IQToolkit.) Вы сказали: «Я не использую LINQ», но ваш код говорит об обратном (он полон LINQ; деревья выражений считаются частью LINQ).   -  person Timwi    schedule 17.11.2010


Ответы (2)


Если речь идет о построении самого дерева выражений, вы можете использовать возможности компилятора C#.

Допустимо передавать лямбда-выражение в прием функции Expression>, если известны аргументы типа Func. Например

 private static void PrintExpression(Expression<Func<int, bool>> lambda)
 {
      Console.WriteLine(lambda.ToString());
 }

можно назвать как

 PrintExpression(a=> a > 0 && a < 5);

Вы можете импровизировать с дженериками как

private static void PrintExpression<T1,T2>(Expression<Func<T1, T2>> lambda)
{
      Console.WriteLine(lambda.ToString());
}

и вызывая его с

   PrintExpression<int, bool>(a=> a > 0 && a < 5);

Для пользовательской печати части выражения вы можете написать простую рекурсивную функцию, которая печатает выражение или любую другую логику, которая вам подходит.

Помните, что лямбда-выражение компилируется в выражение во время компиляции, поэтому его нельзя заменить уже скомпилированным Func.

В качестве альтернативы этому вы всегда можете создать собственный поставщик запросов, но это будет немного отклоняться от цели, так как вам нужно будет связать его с каким-то запросом (опять же на заказ).

person Om Deshmane    schedule 17.11.2010

Попробуйте что-то вроде этого:

static string GetExpressionString<T>(Expression<Func<T, bool>> expression)
{
    return expression.Body.ToString();
}

Использование как таковое:

string s = GetExpressionString<Foo>(foo => foo.X == 5 && foo.Y < 3);

Что вернет:

((foo.X = 5) && (foo.Y < 3))
person Matthew King    schedule 17.11.2010
comment
Ого, клянусь, ответа mho не было, когда я разместил свой! Его немного более глубокий, но я думаю, что я оставлю свой здесь. - person Matthew King; 17.11.2010
comment
Я хотел бы добавить, что удаление любой строгой типизации и разрешение объекта было бы гораздо полезнее. :) - person Lazlo; 03.12.2010