我正在研究LINQ to SQL转换器。它应该将LINQ查询转换为SQL。我专注于创建查询的WHERE部分。 我正在遍历LINQ表达式树,然后我遇到一个问题,我无法获得传递给包含LINQ调用的方法的实际参数的值。
注意:我没有使用LINQ to SQL,也没有使用Entity Framework,也没有使用NHibernate,因为我无法在VB6 Legacy系统中使用它。
所以我想要达到的目的是在高级别的地方打电话:
int? parameterForCall = cmb.SelectedValue;
然后我有一个像这样的方法,它在ExpenseDAL
类中调用BaseDAL<Expense>.GetAll(X)
:
public IList<Expense> GetAll(int? parameterForCall)
{
IList<Expense> expenses = BaseDAL<Expense>.GetAll(t => t.Fixed ==
parameterForCall);
}
GetAll
方法有这样的签名:
public static IList<T> GetAll(Expression<Func<T, bool>> predicate = null);
然后我调用将表达式转换为SQL的GetCondition
方法:
private static string GetCondition(Expression predicate = null);
这是一个递归函数。在其中我遇到了一个情况,我需要获取传递给GetAll
表达式的参数,名为parameterForCall
。
问题是我可以这样写:
dynamic value = (predicate as ConstantExpression);
在ImmediateWindow中我可以看到value.Value是这样写的:
{FMC.Proxy.Common.BaseDAL.}
parameterForCall: 19
但我无法达到值19.我想要它,所以我可以将它转换为值以放入SQL字符串。
有没有人知道如何获得价值19所以我可以在代码中使用它?
答案 0 :(得分:1)
您只需从已经获得的dynamic
获取该属性:
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);
}
如果您执行Test(19)
,则输出为parameterForCall = 19
。
答案 1 :(得分:1)
我的回答是假设 - 并且您的问题支持此假设 - 传递到GetCondition
的谓词属于ConstantExpression
类型。
获取该值并非易事,因为parameterForCall
是在自动生成的类中捕获的。当您查看(predicate as ConstantExpression).Value.GetType()
的输出时,您可以看到。在我的例子中,这输出:
UserQuery+<>c__DisplayClass0
这个类又有一个名为parameterForCall
的公共字段。现在,您有两种可能性来获得该值:
您知道该字段的名称,因为您可以控制创建此表达式的方法。在这种情况下,您可以使用此代码获取值:
var constantExpression = (ConstantExpression)predicate;
dynamic autoGeneratedClass = constantExpression.Value;
object value = autoGeneratedClass.parameterForCall;
value.GetType()
将返回System.Int32
,value
将是一个带有值19的盒装int。
您不知道该字段的名称。在那种情况下,它更难。您可以使用反射来获取唯一的公共可见字段的值,但是如果这样做,您会对自动生成的类做出很多假设。
答案 2 :(得分:0)
希望这个Stackoverflow回答有帮助
expression trees linq get value of a parameter?
基本上,您可能必须先编译表达式,然后才能以编程方式获取属性值。
但要注意性能损失。祝你好运。