dev*_*ife 19 c# expression-trees c#-4.0
我创建了一个覆盖VisitConstant的ExpressionVisitor实现.但是,当我创建一个利用局部变量的表达式时,我似乎无法获得变量的实际值.
public class Person
{
public string FirstName { get; set; }
}
string name = "Michael";
Expression<Func<Person, object>> exp = p => p.FirstName == name;
Run Code Online (Sandbox Code Playgroud)
我如何在ConstantExpression中获取变量"name"的值?我唯一能想到的是:
string fieldValue = value.GetType().GetFields().First().GetValue(value).ToString();
Run Code Online (Sandbox Code Playgroud)
显然,这并不适合作为非常灵活的......
一个稍微复杂的例子如下:
Person localPerson = new Person { FirstName = "Michael" };
Expression<Func<Person, object>> exp = p => p.FirstName == localPerson.FirstName;
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 32
编辑:好的,由于AHM的评论,你现在的意思更清楚了.
基本上,代码被编译为name在单独的类中捕获- 然后应用字段访问以从常量表达式获取其值,该常量表达式引用它的实例.(它必须这样做,因为您可以name 在创建表达式后更改值- 但表达式捕获变量,而不是值.)
所以你实际上并不希望将上做任何事情ConstantExpression的VisitConstant-你想在现场访问工作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);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:好的,稍微涉及访问者类的版本:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在运行:
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));
Run Code Online (Sandbox Code Playgroud)
给出结果:
Before: p => Convert((p.FirstName ==
value(Program+<>c__DisplayClass1).localPerson.FirstName))
After: p => Convert((p.FirstName == "Jon"))
Run Code Online (Sandbox Code Playgroud)
Mer*_*OWA 17
以下是我为您列出的两种情况解决的问题.
基本上假设'=='的右侧可以被视为不带参数并返回值的函数,它可以编译为C#委托并调用以检索此值而无需担心代码上的确切内容右手边.
所以基本的示例代码如下
class Visitor : ExpressionVisitor {
protected override Expression VisitBinary( BinaryExpression node ) {
var memberLeft = node.Left as MemberExpression;
if ( memberLeft != null && memberLeft.Expression is ParameterExpression ) {
var f = Expression.Lambda( node.Right ).Compile();
var value = f.DynamicInvoke();
}
return base.VisitBinary( node );
}
}
Run Code Online (Sandbox Code Playgroud)
它寻找一个二进制op寻找"arg.member == something"然后只编译/评估右侧,对于这两个例子,你提供的结果是一个字符串"Michael".
注意,如果您的右侧涉及使用lamda参数,则会失败
p.FirstName == CallSomeFunc(p.FirstName)
| 归档时间: |
|
| 查看次数: |
7595 次 |
| 最近记录: |