下面是我的问题的简单演示代码。
[TestClass]
public class ExpressionTests
{
[TestMethod]
public void TestParam()
{
Search<Student>(s => s.Id == 1L);
GetStudent(1L);
}
private void GetStudent(long id)
{
Search<Student>(s => s.Id == id);
}
private void Search<T>(Expression<Func<T, bool>> filter)
{
var visitor = new MyExpressionVisitor();
visitor.Visit(filter);
}
}
public class MyExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitConstant(ConstantExpression node)
{
Assert.AreEqual(1L, node.Value);
return base.VisitConstant(node);
}
}
TestParam
方法导致VisitConstant
在两个不同的路径上调用:
1 TestParam
.-> Search
->VisitConstant
在这个执行路径中,传递给Search
方法的常量表达式 (1L) 是一个实常量值。到这里,一切正常,assert按预期成功。当VisitConstant
通过第一个路径调用时node.Value.GetType()
isInt64
和它的.Value
is 1L
。
2 TestParam
.-> GetStudent
-> Search
->VisitConstant
在这个执行路径常量表达式 (id: 1L) 中,GetStudent
作为参数并传递给Search
闭包内的方法。
问题
问题出在第二条执行路径上。当VisitConstant
通过第二条路径调用node.Value.GetType()
时MyProject.Tests.ExpressionTests+<>c__DisplayClass0
,该类有一个名为id
(与GetStudent
方法的参数相同)的公共字段,其值为1L
.
问题
如何id
在第二条路径中获得价值?我知道闭包,什么是 aDisplayClass
以及为什么在编译时创建它等。我只对获取它的字段值感兴趣。我能想到的一件事是,通过反射。像下面这样的东西,但它看起来并不整洁。
node.Value.GetType().GetFields()[0].GetValue(node.Value);
奖金问题
在使用获取id
值的代码时,我更改了VisitConstant
如下方法(但这不会解决我的问题)并得到一个异常说“'object'不包含'id'的定义”
奖金问题
由于动态是在运行时解析并DisplayClass
在编译时创建的,为什么我们不能使用 访问它的字段dynamic
?虽然下面的代码可以工作,但我希望该代码也可以工作。
var st = new {Id = 1L};
object o = st;
dynamic dy = o;
Assert.AreEqual(1L, dy.Id);