编辑:好的,感谢 AHM 的评论,您的意思现在更清楚了。
基本上,代码被编译以在单独的类中捕获name - 然后应用字段访问以从引用它的实例的常量表达式中获取其值。 (它必须这样做,因为您可以在创建表达式之后更改 name 的值 - 但表达式捕获的是变量,而不是值。)
因此,您实际上并不想在VisitConstant 中的ConstantExpression 上做任何事情——您想在VisitMember 中进行字段访问。您需要从 ConstantExpression 子节点获取值,然后将其提供给 FieldInfo 以获取值:
using System;
using System.Linq.Expressions;
using System.Reflection;
public class Person
{
public string FirstName { get; set; }
}
static class Program
{
static void Main(string[] args)
{
string name = "Michael";
Expression<Func<Person, object>> exp = p => p.FirstName == name;
new Visitor().Visit(exp);
}
}
class Visitor : ExpressionVisitor
{
protected override Expression VisitMember
(MemberExpression member)
{
if (member.Expression is ConstantExpression &&
member.Member is FieldInfo)
{
object container =
((ConstantExpression)member.Expression).Value;
object value = ((FieldInfo)member.Member).GetValue(container);
Console.WriteLine("Got value: {0}", value);
}
return base.VisitMember(member);
}
}
编辑:好的,稍微复杂一点的访问者类:
class Visitor : ExpressionVisitor
{
protected override Expression VisitMember
(MemberExpression memberExpression)
{
// Recurse down to see if we can simplify...
var expression = Visit(memberExpression.Expression);
// If we've ended up with a constant, and it's a property or a field,
// we can simplify ourselves to a constant
if (expression is ConstantExpression)
{
object container = ((ConstantExpression) expression).Value;
var member = memberExpression.Member;
if (member is FieldInfo)
{
object value = ((FieldInfo)member).GetValue(container);
return Expression.Constant(value);
}
if (member is PropertyInfo)
{
object value = ((PropertyInfo)member).GetValue(container, null);
return Expression.Constant(value);
}
}
return base.VisitMember(memberExpression);
}
}
现在运行它:
var localPerson = new Person { FirstName = "Jon" };
Expression<Func<Person, object>> exp = p => p.FirstName == localPerson.FirstName;
Console.WriteLine("Before: {0}", exp);
Console.WriteLine("After: {0}", new Visitor().Visit(exp));
给出结果:
Before: p => Convert((p.FirstName ==
value(Program+<>c__DisplayClass1).localPerson.FirstName))
After: p => Convert((p.FirstName == "Jon"))