Parsing Conditional Expressions to String
Asked Answered
C

2

5

I'm looking for a way of parsing a conditional expression to a string.

The best example I can think of is LINQ-to-SQL. It uses ExpressionVisitors to format "Where" clauses. Example:

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

That would translate into the following string (approximately, MSSQL is not current for me):

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

From what I've read, this was done using the ExpressionVisitor class, as explained in this article: Link

Now the problem is that I don't use LINQ, but I need this particular functionality. Is there a way of parsing a condition like that? I'm willing to do anything with reflection, delegates, lambda, etc.

Honestly, I don't think it's possible, but my brain is a bit fried (read: be nice if the question is ridiculous), so I figured I might just as well give S/O a try.

EDIT: Final usage example:

// 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"

EDIT 2: Yes, a number can be lower than 3 and equal to 5. Told you my brain is fried.

Compaction answered 17/11, 2010 at 1:57 Comment(1)
LINQ-to-SQL does exactly this. If you write your own, you’d be reimplementing LINQ-to-SQL, which already exists — that seems like a pointless effort. (Yet people have done it; google for IQToolkit for example.) You said “I don't use LINQ” but your code says the opposite (it’s full of LINQ; expression trees are considered to be part of LINQ).Kauppi
I
4

If it is about about building the expression tree itself, then you could leverage C# compiler abilities.

It is legal to pass a lambda expression to a function acception an Expression>, as long as type arguments of Func are known. For example

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

can be called as

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

You can improvise with generics as

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

and calling it with

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

For custom printing of the expression part, you can write a simple recursive function that prints an expression or any other logic that suits you.

Remember, the lambda expression is compiled into an Expression at compile time - so can't subsititute it with already compiled Func.

As an alternative to this, you can always build a custom query provider, but that would be slightly deviating from the purpose - as you'd need to bind it some sort of queryable (custom again).

Idolatry answered 17/11, 2010 at 3:50 Comment(0)
M
3

Try something like this:

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

Usage as so:

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

Which will return:

((foo.X = 5) && (foo.Y < 3))
Motte answered 17/11, 2010 at 4:11 Comment(2)
Oh wow, I swear mho's answer wasn't here when I posted mine! His is a bit more in-depth, but I'll leave mine here I guess.Motte
I'd like to add that removing any strong typing and allowing "object" would be much more useful. :)Compaction

© 2022 - 2024 — McMap. All rights reserved.