ExpressionTreeToString icon indicating copy to clipboard operation
ExpressionTreeToString copied to clipboard

Different Behavior than I expected

Open danielscatigno-ncpc opened this issue 3 years ago • 3 comments

Hi this is more like a question, I have not found the answer anywhere

I'm trying to convert an Expression to string 1)

Expression<Func<ProjetoProcessamentoViewModel,bool>> exp = x=>x.IdProjeto==3;
exp.ToString(BuiltinRenderer.DynamicLinq,"C#");

The output is ""IdProjeto == 3""

And ok That is what I expected but when I convert the value into a variable: 2)

int IdProjeto=3;

Expression<Func<ProjetoProcessamentoViewModel,bool>> exp = x=>x.IdProjeto==IdProjeto;
exp.ToString(BuiltinRenderer.DynamicLinq,"C#");

the output is: "// @0 = IdProjeto\r\n\r\n"IdProjeto == @0""

Is there any way that the variable be converted to its value so the output is the same as example 1?

danielscatigno-ncpc avatar Jul 26 '22 20:07 danielscatigno-ncpc

The library doesn't support this behavior, because the expression tree doesn't reflect it. What should be the output of the following code?

int IdProjeto = 3;
Expression<Func<ProjetoProcessamentoViewModel, bool>> exp = x => x.IdProjeto == IdProjeto;
Console.WriteLine(exp.ToString(BuiltinRenderer.CSharp, "C#"));
IdProjeto = 5;
Console.WriteLine(exp.ToString(BuiltinRenderer.CSharp, "C#"));

Since the expression tree hasn't changed, the output should be the same both before and after the assignment.

What you might do is replace the variable with the value:

Expression<Func<Model, bool>> exp = x => x.IdProjeto == IdProjeto;
Console.WriteLine(exp.ToString(BuiltinRenderer.CSharp, "C#").Replace(" IdProjeto", " " + IdProjeto.ToString()));

zspitz avatar Jul 31 '22 09:07 zspitz

I can't do this , I'm sending the expression as an string to be parsed by Dynamic Linq (API method), I don't have the value of the variable (IdProjeto for example) in the moment that the expression is parsed

I've managed to get the variable value using something like

MemberExpression right = (MemberExpression)((BinaryExpression)where.Body).Left;
value = Expression.Lambda(right).Compile().DynamicInvoke();

But the case is that my expression can be a complex one and it's hard to find all variables values

I was also looking for a way to convert a System.Linq.Expressions.FieldExpression to a System.Linq.Expressions.ConstantExpression but I have not succeeded

danielscatigno-ncpc avatar Aug 05 '22 15:08 danielscatigno-ncpc

You can create a custom renderer and register it as described here.

In your case I would suggest writing a class that inherits from DynamicLinqWriterVisitor, providing an overriding implementation of the WriteMemberAccess method that passes in to WriteNode a ConstantExpression with the value of the variable if the MemberAccessExpression's object is a closure object (as in the base implementation).

There is a TryExtractValue extension method in ZSpitz.Util which you may find useful.

zspitz avatar Aug 06 '22 20:08 zspitz

You can create a custom renderer and register it as described here.

In your case I would suggest writing a class that inherits from DynamicLinqWriterVisitor, providing an overriding implementation of the WriteMemberAccess method that passes in to WriteNode a ConstantExpression with the value of the variable if the MemberAccessExpression's object is a closure object (as in the base implementation).

There is a TryExtractValue extension method in ZSpitz.Util which you may find useful.

zspitz avatar Sep 12 '22 11:09 zspitz