- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
下面是我的问题的简单演示代码。
[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
在此执行路径中常量表达式(1L)传递给Search
method 是一个实常数值。到这里,一切正常,assert如期成功。当VisitConstant
通过第一个路径调用 node.Value.GetType()
是Int64
及其 .Value
是1L
.
2. TestParam
-> GetStudent
-> Search
-> VisitConstant
在此执行路径常量表达式(id:1L)中,被GetStudent
取走作为参数传递给 Search
闭包中的方法。
问题
问题出在第二个执行路径上。当VisitConstant
通过第二条路径调用 node.Value.GetType()
是MyProject.Tests.ExpressionTests+<>c__DisplayClass0
这个类有一个名为 id
的公共(public)字段(与 GetStudent
方法的参数相同)其值为 1L
.
问题
我怎样才能得到 id
第二条路径的值(value)?我知道闭包,多好的DisplayClass
是以及为什么它是在编译时创建的等等。我只对获取它的字段值感兴趣。我能想到的一件事是,通过反射(reflection)。像下面这样的东西,但它看起来并不整洁。
node.Value.GetType().GetFields()[0].GetValue(node.Value);
奖金问题
在玩弄获取 id
的代码时我更改的值 VisitConstant
像下面这样的方法(虽然它不会解决我的问题)并得到一个异常说 “'object' does not contain a definition for 'id'”
奖励问题
由于动态在运行时得到解决并且 DisplayClass
是在编译时创建的,为什么我们不能用 dynamic
访问它的字段? ?虽然下面的代码有效,但我希望该代码也能正常工作。
var st = new {Id = 1L};
object o = st;
dynamic dy = o;
Assert.AreEqual(1L, dy.Id);
最佳答案
VisitConstant
在这里无济于事,因为它接收编译器构造的 ConstantExpression
,它使用私有(private)匿名类的对象来存储值 lambda 已关闭(DisplayClassxxx
)
相反,我们应该重写 VisitMember
方法并检查它的 MemberExpression
,它已经将 ConstantExpression
作为内部 Expression
.
这是工作测试,几乎没有反射(reflection)。
[TestClass]
public class UnitTest2
{
[TestMethod]
public void TestMethod2()
{
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 MyExpressionVisitor2();
visitor.Visit(filter.Body);
}
}
//ExpressionVisitor
public class MyExpressionVisitor2 : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
switch (node.Expression.NodeType)
{
case ExpressionType.Constant:
case ExpressionType.MemberAccess:
{
var cleanNode = GetMemberConstant(node);
//Test
Assert.AreEqual(1L, cleanNode.Value);
return cleanNode;
}
default:
{
return base.VisitMember(node);
}
}
}
private static ConstantExpression GetMemberConstant(MemberExpression node)
{
object value;
if (node.Member.MemberType == MemberTypes.Field)
{
value = GetFieldValue(node);
}
else if (node.Member.MemberType == MemberTypes.Property)
{
value = GetPropertyValue(node);
}
else
{
throw new NotSupportedException();
}
return Expression.Constant(value, node.Type);
}
private static object GetFieldValue(MemberExpression node)
{
var fieldInfo = (FieldInfo)node.Member;
var instance = (node.Expression == null) ? null : TryEvaluate(node.Expression).Value;
return fieldInfo.GetValue(instance);
}
private static object GetPropertyValue(MemberExpression node)
{
var propertyInfo = (PropertyInfo)node.Member;
var instance = (node.Expression == null) ? null : TryEvaluate(node.Expression).Value;
return propertyInfo.GetValue(instance, null);
}
private static ConstantExpression TryEvaluate(Expression expression)
{
if (expression.NodeType == ExpressionType.Constant)
{
return (ConstantExpression)expression;
}
throw new NotSupportedException();
}
}
关于c# - 由于关闭而将实际值包装到 DisplayClass 中时获取 ConstantExpression.Value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25705339/
给定Msdn:常量表达式是可以在编译时完全计算的表达式。 但是在下面的示例代码中,我有一个无法在编译时评估的 contantExpression。 我应该错过一些东西,但是什么? public cla
给定 Msdn:常量表达式是可以在编译时完全求值的表达式。 但是在下面的示例代码中,我有一个无法在编译时求值的 contantExpression。 我应该错过了什么,但是什么? public cla
当 ConstantExpression 值为 null 时,如何确定它的类型?我以前一直使用以下代码检测类型,但是当 ConstantExpression 值为 null 时它会导致 null 异常
我正在寻找一个值 var guid = Guid.Parse("SOMEGUID-GUID-GUID-GUID-SOMEGUIDGUID"); Expression> selector = x =>
我创建了一个覆盖 VisitConstant 的 ExpressionVisitor 实现。但是,当我创建一个使用局部变量的表达式时,我似乎无法获得该变量的实际值。 public class Pers
无论怎么想,我都不是表达式树大师,我拥有的代码如下所示: int external = 10; using(var session = new Session()) {
我尝试实现自己的表达式序列化器/反序列化器,以便通过服务传递它(我想实现我自己的 EF Core 服务端点)。所以,现在我对 LambdaExpressions 中的集合有问题。例如, var dat
我尝试实现自己的表达式序列化器/反序列化器,以便通过服务传递它(我想实现我自己的 EF Core 服务端点)。所以,现在我对 LambdaExpressions 中的集合有问题。例如, var dat
我有一些代码生成表达式作为数据库中读取的“where”语句传递,我正在尝试加快速度。 下面的示例使用 where 语句来匹配具有传入值的表的 PK: private Expression MakeWh
下面是我的问题的简单演示代码。 [TestClass] public class ExpressionTests { [TestMethod] public void TestPara
这个问题在 NHibernate 2 和 3 中都会出现。我有一个类 A,它有一个类 B 的成员集。直接查询类可以很好地执行。但是,当我将涉及类 B 的表达式之一传递到方法中时,出现以下错误: Sys
这个问题在 NHibernate 2 和 3 中都会出现。我有一个类 A,它有一个类 B 的成员集。直接查询类可以很好地执行。但是,当我将涉及类 B 的表达式之一传递到方法中时,出现以下错误: Sys
我是一名优秀的程序员,十分优秀!