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