gpt4 book ai didi

c# - 由于关闭而将实际值包装到 DisplayClass 中时获取 ConstantExpression.Value

转载 作者:太空狗 更新时间:2023-10-29 18:35:26 26 4
gpt4 key购买 nike

下面是我的问题的简单演示代码。

[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及其 .Value1L .

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'”

enter image description here

奖励问题

由于动态在运行时得到解决并且 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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com