访问成员表达式的值

Sch*_*ime 63 c# linq lambda expression-trees

如果我有产品.

var p = new Product { Price = 30 };
Run Code Online (Sandbox Code Playgroud)

我有以下linq查询.

var q = repo.Products().Where(x=>x.Price == p.Price).ToList()
Run Code Online (Sandbox Code Playgroud)

在IQueryable提供程序中,我得到一个包含常量表达式的p.Price的MemberExpression,但是我似乎无法从它获得值"30".

更新 我试过这个,但它似乎不起作用.

var memberExpression = (MemberExpression)GetRootConstantExpression(m);
var fi = (PropertyInfo)memberExpression.Member;
var val = fi.GetValue(((ConstantExpression)memberExpression.Expression).Value, null);
Run Code Online (Sandbox Code Playgroud)

干杯.

Bry*_*tts 102

您可以编译和调用其主体是成员访问权限的lambda表达式:

private object GetValue(MemberExpression member)
{
    var objectMember = Expression.Convert(member, typeof(object));

    var getterLambda = Expression.Lambda<Func<object>>(objectMember);

    var getter = getterLambda.Compile();

    return getter();
}
Run Code Online (Sandbox Code Playgroud)

解析表达式树时,本地评估是一种常用技术.LINQ to SQL在很多地方都做到了这一点.

  • 不得不添加:var expression = Expression.Convert(member,typeof(object)); 在函数的第一行用双重转换来修复上面的错误! (3认同)

Gle*_*lar 30

 MemberExpression right = (MemberExpression)((BinaryExpression)p.Body).Right;
 Expression.Lambda(right).Compile().DynamicInvoke();
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 24

常量表达式将指向编译器生成的捕获类.我没有包括决策点等,但是这里是如何得到30:

var p = new Product { Price = 30 };
Expression<Func<Product, bool>> predicate = x => x.Price == p.Price;
BinaryExpression eq = (BinaryExpression)predicate.Body;
MemberExpression productToPrice = (MemberExpression)eq.Right;
MemberExpression captureToProduct = (MemberExpression)productToPrice.Expression;
ConstantExpression captureConst = (ConstantExpression)captureToProduct.Expression;
object product = ((FieldInfo)captureToProduct.Member).GetValue(captureConst.Value);
object price = ((PropertyInfo)productToPrice.Member).GetValue(product, null);
Run Code Online (Sandbox Code Playgroud)

price现在30.请注意,我假设这Price是一个属性,但实际上你会编写一个GetValue处理属性/字段的方法.

  • @Schotime - 的确如此.要以通用方式处理此问题,请参阅此处的"Evaluate"和"TryEvaluate":http://code.google.com/p/protobuf-net/source/browse/trunk/protobuf-net.Extensions/ServiceModel/Client/ ProtoClientExtensions.cs (3认同)
  • @AshrafSabry 取决于你做了多少次,以及你是否在重用委托 (2认同)

Ale*_*urt 7

截至 2020 年

这个辅助方法将优雅地检索任何表达式值,而无需“编译黑客”:

public static object GetMemberExpressionValue (MemberExpression expression)
{
    // Dependency chain of a MemberExpression is of the form:
    // MemberExpression expression
    //    MemberExpression expression.Expression
    //        ... MemberExpression expression.[...].Expression
    //            ConstantExpression expression.[...].Expression.Expression <- base object
    var dependencyChain = new List<MemberExpression>();
    var pointingExpression = expression;
    while (pointingExpression != null)
    {
        dependencyChain.Add(pointingExpression);
        pointingExpression = pointingExpression.Expression as MemberExpression;
    }

    if (!(dependencyChain.Last().Expression is ConstantExpression baseExpression))
    {
        throw new Exception(
            $"Last expression {dependencyChain.Last().Expression} of dependency chain of {expression} is not a constant." +
            "Thus the expression value cannot be found.");
    }

    var resolvedValue = baseExpression.Value;

    for (var i = dependencyChain.Count; i > 0; i--)
    {
        var expr = dependencyChain[i - 1];
        resolvedValue = new PropOrField(expr.Member).GetValue(resolvedValue);
    }

    return resolvedValue;
}
Run Code Online (Sandbox Code Playgroud)

PropOrField班级 :

public class PropOrField
{
    public readonly MemberInfo MemberInfo;

    public PropOrField (MemberInfo memberInfo)
    {
        if (!(memberInfo is PropertyInfo) && !(memberInfo is FieldInfo))
        {
            throw new Exception(
                $"{nameof(memberInfo)} must either be {nameof(PropertyInfo)} or {nameof(FieldInfo)}");
        }

        MemberInfo = memberInfo;
    }

    public object GetValue (object source)
    {
        if (MemberInfo is PropertyInfo propertyInfo) return propertyInfo.GetValue(source);
        if (MemberInfo is FieldInfo fieldInfo) return fieldInfo.GetValue(source);

        return null;
    }

    public void SetValue (object target, object source)
    {
        if (MemberInfo is PropertyInfo propertyInfo) propertyInfo.SetValue(target, source);
        if (MemberInfo is FieldInfo fieldInfo) fieldInfo.SetValue(target, source);
    }

    public Type GetMemberType ()
    {
        if (MemberInfo is PropertyInfo propertyInfo) return propertyInfo.PropertyType;
        if (MemberInfo is FieldInfo fieldInfo) return fieldInfo.FieldType;

        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)


t_w*_*sop 5

如果你有课:

public class Item
{
    public int Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和对象的实例:

var myItem = new Item { Id = 7 };
Run Code Online (Sandbox Code Playgroud)

您可以使用以下代码使用表达式获取 Id 的值:

Expression<Func<Item, int>> exp = x => x.Id;
var me = exp.Body as MemberExpression;
var propInfo = me.Member as PropertyInfo;
var myValue = propInfo.GetValue(myItem, null);
Run Code Online (Sandbox Code Playgroud)

myValue 将包含“7”