C# 解析传递给使用LINQ表达式的方法的LINQ参数

C# 解析传递给使用LINQ表达式的方法的LINQ参数,c#,linq,expression,expression-trees,C#,Linq,Expression,Expression Trees,我正在开发LINQ到SQL转换器。它应该将LINQ查询转换为SQL。我专注于创建查询的WHERE部分。 我正在遍历LINQ表达式树,然后遇到了一个问题,我无法获得传递给包含LINQ调用的方法的实际参数的值 注意:我没有使用LINQtoSQL,也没有使用实体框架,也没有使用NHibernate,因为游戏中有VB6遗留系统,所以我不能使用 因此,我试图实现的是在高层的某个地方: int? parameterForCall = cmb.SelectedValue; 然后我有一个这样的方法,它在Exp

我正在开发LINQ到SQL转换器。它应该将LINQ查询转换为SQL。我专注于创建查询的WHERE部分。 我正在遍历LINQ表达式树,然后遇到了一个问题,我无法获得传递给包含LINQ调用的方法的实际参数的值

注意:我没有使用LINQtoSQL,也没有使用实体框架,也没有使用NHibernate,因为游戏中有VB6遗留系统,所以我不能使用

因此,我试图实现的是在高层的某个地方:

int? parameterForCall = cmb.SelectedValue;
然后我有一个这样的方法,它在
ExpenseDAL
类中调用
BaseDAL.GetAll(X)

然后调用将表达式转换为SQL的
GetCondition
方法:

private static string GetCondition(Expression predicate = null);
它是一个递归函数。在这种情况下,我需要获取传递给
GetAll
表达式的参数,名为
parameterForCall

问题是,我可以这样写:

dynamic value = (predicate as ConstantExpression);
在即时窗口中,我可以看到这个值。值是这样写的:

public static IList<T> GetAll(Expression<Func<T, bool>> predicate = null);
{FMC.Proxy.Common.BaseDAL.}
    parameterForCall: 19
但我无法得到19的值。我想要它,这样我就可以把它转换成值,放到SQL字符串中


有人知道如何获得值19以便我可以在代码中使用它吗?

希望这个答案有帮助

基本上,在以编程方式获取属性值之前,您可能必须编译表达式


但要注意表现的惩罚。祝您好运。

您只需从
动态
获取您已经获得的属性:

dynamic value = (predicate as ConstantExpression);
int? parameterForCall = value.parameterForCall;
如果不知道参数的名称(可能还有类型),可以使用反射。您要查找的参数作为对象的公共字段存在,该对象由
ConstantExpression.Value
返回。这不是任何地方指定的东西,因此使用它的风险由您自己承担

这段代码演示了:

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);
}
class Expense{public int Fixed{get;set;}
无效测试(int?参数FORCALL){
表达式谓词=t=>t.Fixed==parameterForCall;
变量参数=(
(恒压)(
(成员表达)(
(二进制表达式)谓词.Body
).对
).表达
).价值;
var fieldInfo=parameter.GetType().GetFields().First();
var name=fieldInfo.name;
var value=fieldInfo.GetValue(参数);
Console.WriteLine(名称+“=”+值);
}

如果执行
Test(19)
输出为
parameterForCall=19

我的回答假设-并且您的问题支持此假设-传递到
GetCondition
的谓词类型为
ConstantExpression

获取该值并不简单,因为
parameterForCall
是在自动生成的类中捕获的。当您查看
(谓词为ConstantExpression.Value.GetType()
的输出时,可以看到这一点。就我而言,这将输出:

UserQuery+<>c__DisplayClass0
value.GetType()
将返回
System.Int32
value
将是一个带框的int,值为19

  • 您不知道该字段的名称。在这种情况下,就更难了。您可以使用反射来获取唯一公共可见字段的值,但如果这样做,您将对自动生成的类做出许多假设


  • 我想知道您如何反思
    autoGeneratedClass
    。与静态类型的对象相比,对动态对象的反射是不同的。您不会对自动生成的类进行反射。您反映了
    常量pression.Value
    ,它是一个
    对象
    。如果你选择选项2“反射”,你就不需要
    autoGeneratedClass
    。@Martin:Haha,你在我的评论帮助下更新了你的答案吗?哇,真便宜。尤其是因为你遗漏了我发布的关于这种方法的警告@马丁:我上一次的评论语调不对,说你便宜是错误的。对此我很抱歉。但是:我故意没有为这个场景提供代码,因为如果OP真的想这样做的话,我想让他请求。为什么?因为我需要更多的研究来更好地指出这种方法可能存在的问题。基本上:(1)“闭包类重用”是由编译器以这样的方式实现的,即在闭包类中捕获多个变量,因此,简单地获取第一个公共字段可能会得到错误的结果。(2) 依赖于实现细节。谢谢,我不得不修改一些部分,但我走上了正确的轨道。另外,是否有方法确定value.Type是否是动态生成的?现在我在看它的名字是否以“”开头。var值=(谓词为常量表达式);动态评估值=value.value;如果(value.Type.Name.StartsWith(“”){evaluatedValue=value.Type.GetFields()[0].GetValue(value.value);}条件+=GetSQLFormattedColumnValue((对象)evaluatedValue);
    UserQuery+<>c__DisplayClass0
    
    var constantExpression = (ConstantExpression)predicate;
    dynamic autoGeneratedClass = constantExpression.Value;
    object value = autoGeneratedClass.parameterForCall;