开发者

Resolving LINQ Parameters that were passed to method in which LINQ Expression is

开发者 https://www.devze.com 2023-04-08 12:30 出处:网络
I am working on LINQ to SQL translator. It should translate LINQ queries to SQL. I am focused on creating WHERE part of the query.

I am working on LINQ to SQL translator. It should translate LINQ queries to SQL. I am focused on creating WHERE part of the query. I am traversing LINQ Expression tree and then I get to a problem that I can't get to the value of actual parameter passed to the method that contains LINQ call.

NOTE: I am not using LINQ to SQL, nor Entity Framework, nor NHibernate because I simply can't since VB6 Legacy system is in the game.

So what I am trying to achieve is to call somewhere on high level this:

int? parameterForCall = cmb.SelectedValue;

Then I have a method like this and it is in ExpenseDAL class that calls BaseDAL<Expense>.GetAll(X):

public IList<Expense> GetAll(int? parameterForCall)
{
    IList<Expense> expenses = BaseDAL<Expense>.GetAll(t => t.Fixed == 
                                                           parameterForCall);
}

GetAll method has signature like this:

public static IList<T> GetAll(Expression<Func<T, bool>> predicate = null);

Then I am calling GetCondition method that converts expression to SQL:

private static string GetCondition(Expression predicate = null);

It is a recursive function. In it I get to a situation that I need to get to parameter that I passed to GetAll expression, named parameterForCall.

The problem is that I can write this:

dynamic value = (predicate as ConstantExpression);

And in ImmediateWindow I can see that value.Value is written like this:

{FMC.Proxy.Common.BaseDAL.}
    parameterForCall: 19

But I can'开发者_开发问答t get to the value 19. And I want it so I can convert it to value to put to SQL string.

Does anyone know how to get to value 19 so I can use it in the code?


My answer assumes - and your question supports this assumption - that the predicate passed into GetCondition is of type ConstantExpression.

It isn't trivial to get that value, because parameterForCall is captured in an automatically generated class. You can see that, when you look at the output of (predicate as ConstantExpression).Value.GetType(). In my case, this outputs:

UserQuery+<>c__DisplayClass0

This class in turn has a public field named parameterForCall. Now, you have two possibilities to get that value:

  1. You know the name of that field, because you control the method in which this Expression is created. In that case, you can use this code to get the value:

    var constantExpression = (ConstantExpression)predicate;
    dynamic autoGeneratedClass = constantExpression.Value;
    object value = autoGeneratedClass.parameterForCall;
    

    value.GetType() will return System.Int32 and the value will be a boxed int with the value 19.

  2. You don't know the name of that field. In that case, it is harder. You could use reflection to get the value of the only public visible field, but if you do this, you would make a lot of assumptions about the automatically generated class.


You simply have to get the property from the dynamic you already got:

dynamic value = (predicate as ConstantExpression);
int? parameterForCall = value.parameterForCall;

If you don't know the name of the parameter (and perhaps the type) you can use reflection. The parameter you are looking for exists as a public field of the object returned by ConstantExpression.Value. This is not something specified anywhere so use it at your own risk.

This small piece of code demonstrates that:

class Expense { public int Fixed { get; set; } }

void Test(int? parameterForCall) {
  Expression<Func<Expense, bool>> predicate = t => t.Fixed == parameterForCall;
  var parameter = (
    (ConstantExpression) (
      (MemberExpression) (
        (BinaryExpression) predicate.Body
      ).Right
    ).Expression
  ).Value;
  var fieldInfo = parameter.GetType().GetFields().First();
  var name = fieldInfo.Name;
  var value = fieldInfo.GetValue(parameter);
  Console.WriteLine(name + " = " + value);
}

If you execute Test(19) the output is parameterForCall = 19.


Hope this Stackoverflow answer helps

expression trees linq get value of a parameter?

Basically you might have to compile the expression before being able to programmatically get the property value.

Watch for performance penalty though. Good luck.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号