C# 由于闭包,当实际值包装到DisplayClass中时获取ConstantPression.Value
下面是我的问题的简单演示代码C# 由于闭包,当实际值包装到DisplayClass中时获取ConstantPression.Value,c#,dynamic,closures,linq-expressions,expressionvisitor,C#,Dynamic,Closures,Linq Expressions,Expressionvisitor,下面是我的问题的简单演示代码 [TestClass] public class ExpressionTests { [TestMethod] public void TestParam() { Search<Student>(s => s.Id == 1L); GetStudent(1L); } private void GetStudent(long id) { Search&
[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);
}
}
奖金问题
在玩获取id
值的代码时,我更改了VisitConstant
方法,如下所示(这不会解决我的问题),并得到一个异常,说“'object'不包含'id'的定义”
奖金问题
由于动态是在运行时解析的,而DisplayClass
是在编译时创建的,为什么我们不能用dynamic
访问它的字段呢?虽然下面的代码可以工作,但我希望代码也可以工作
var st = new {Id = 1L};
object o = st;
dynamic dy = o;
Assert.AreEqual(1L, dy.Id);
,并包括执行此操作的代码。基本上,您可以创建一个只表示该子表达式的表达式,将其编译为委托,然后执行该委托。(本文还解释了如何识别可计算的子表达式,但我猜您对此不感兴趣。)
使用本文中的代码,将代码修改为以下内容将有效:
private void Search<T>(Expression<Func<T, bool>> filter)
{
new MyExpressionVisitor().Visit(Evaluator.PartialEval(filter));
}
private void搜索(表达式过滤器)
{
新建MyExpressionVisitor().Visit(Evaluator.PartialEval(filter));
}
由于动态是在运行时解析的,而DisplayClass
是在编译时创建的,为什么我们不能用dynamic
访问它的字段呢
因为DisplayClass
是嵌套在ExpressionTests
中的private
类,所以MyExpressionVisitor
中的代码无法访问其成员
如果将MyExpressionVisitor
设置为ExpressionTests
中的嵌套类,dynamic
将开始处理DisplayClass
匿名类型不会以这种方式运行,因为它们不会作为嵌套的
私有类型发出。VisitConstant
在这里没有帮助,因为它接收一个编译器,该编译器使用私有匿名类的对象来存储值lambda已关闭(DisplayClassxxx
)
相反,我们应该重写VisitMember
方法,并检查其MemberExpression
,该方法已将ConstantExpression
作为内部表达式
这是一个工作测试,几乎没有反射
[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();
}
}
[TestClass]
公共类UnitTest2
{
[测试方法]
公共void TestMethod2()
{
搜索(s=>s.Id==1L);
GetStudent(1L);
}
私人学生(长id)
{
搜索(s=>s.Id==Id);
}
专用无效搜索(表达式筛选器)
{
var visitor=new MyExpressionVisitor2();
visitor.Visit(filter.Body);
}
}
//表情访客
公共类MyExpressionVisitor 2:ExpressionVisitor
{
受保护的重写表达式VisitMember(MemberExpression节点)
{
开关(node.Expression.NodeType)
{
大小写表达式类型。常量:
case ExpressionType.MemberAccess:
{
var cleanNode=GetMemberConstant(节点);
//试验
aresequal(1L,cleanNode.Value);
返回cleanNode;
}
违约:
{
返回base.VisitMember(节点);
}
}
}
私有静态常量表达式GetMemberConstant(MemberExpression节点)
{
目标价值;
if(node.Member.MemberType==MemberTypes.Field)
{
值=GetFieldValue(节点);
}
else if(node.Member.MemberType==MemberTypes.Property)
{
value=GetPropertyValue(节点);
}
其他的
{
抛出新的NotSupportedException();
}
返回表达式.Constant(值、节点.Type);
}
私有静态对象GetFieldValue(MemberExpression节点)
{
var fieldInfo=(fieldInfo)node.Member;
var实例=(node.Expression==null)?null:tryeevaluate(node.Expression).Value;
返回fieldInfo.GetValue(实例);
}
私有静态对象GetPropertyValue(MemberExpression节点)
{
var propertyInfo=(propertyInfo)node.Member;
var实例=(node.Expression==null)?null:tryeevaluate(node.Expression).Value;
返回propertyInfo.GetValue(实例,null);
}
私有静态常量表达式TryEvaluate(表达式)
{
if(expression.NodeType==ExpressionType.Constant)
{
返回(ConstantExpression)表达式;
}
抛出新的NotSupportedException();
}
}
不错!这是获取闭包底层值的最快方法,这应该是公认的答案。
[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();
}
}