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();

    }
}