Разбор условных выражений в строку
Я ищу способ парсинга условного выражения в строку.
Лучший пример, который я могу придумать, это 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-building-an-iqueryable-provider-part-ii.aspx
Теперь проблема в том, что я не использую LINQ, но мне нужна именно эта функциональность. Есть ли способ разбора такого состояния? Я готов сделать все что угодно с рефлексией, делегатами, лямбдами и т. Д.
Честно говоря, я не думаю, что это возможно, но мой мозг немного зажарен (читай: будь хорош, если вопрос смешной), поэтому я решил, что с таким же успехом могу попробовать S/O.
РЕДАКТИРОВАТЬ: Окончательный пример использования:
// 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. Сказал вам, что мой мозг жарен.
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);
Для пользовательской печати части выражения вы можете написать простую рекурсивную функцию, которая печатает выражение или любую другую подходящую вам логику.
Помните, что лямбда-выражение компилируется в Expression во время компиляции - поэтому не может заменить его уже скомпилированным Func.
В качестве альтернативы этому вы всегда можете создать пользовательский поставщик запросов, но это будет слегка отклоняться от цели - поскольку вам нужно будет связать его с каким-либо типом запроса (опять же, пользовательским).
Попробуйте что-то вроде этого:
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))