代码之家  ›  专栏  ›  技术社区  ›  Schotime

访问成员表达式的值

  •  59
  • Schotime  · 技术社区  · 16 年前

    如果我有产品。

    var p = new Product { Price = 30 };
    

    var q = repo.Products().Where(x=>x.Price == p.Price).ToList()
    

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

    我试过这个,但似乎不起作用。

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

    8 回复  |  直到 16 年前
        1
  •  121
  •   Bryan Watts    16 年前

    可以编译和调用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();
    }
    

    局部求值是解析表达式树时常用的技术。linqtosql在很多地方都能做到这一点。

        2
  •  35
  •   ysrb    13 年前
     MemberExpression right = (MemberExpression)((BinaryExpression)p.Body).Right;
     Expression.Lambda(right).Compile().DynamicInvoke();
    
        3
  •  26
  •   Marc Gravell    16 年前

    常量表达式将指向编译器生成的捕获类。我没有包括决策点等,但下面是如何从中获得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);
    

    price 是现在 30 Price GetValue 处理属性/字段的方法。

        4
  •  3
  •   Fabian Heimbürger    9 年前

    使用 Expression.Lambda(myParameterlessExpression).Compile().Invoke()

    • .Compile() 缓慢的 Invoke -不过,之后的调用速度非常快,对于简单的算术表达式或成员访问只需要几纳秒。
    • .Compile() 在应用程序完成之前不能释放

    Compile() 为了避免这些问题,或者缓存已编译的委托以重新使用它们。 This 解释 属于 Expressions 以及 -避免内存泄漏!

        5
  •  2
  •   t_warsop    5 年前

    如果你上过课:

    public class Item
    {
        public int Id { get; set; }
    }
    

    var myItem = new Item { Id = 7 };
    

    可以使用以下代码的表达式获取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);
    

        6
  •  1
  •   Kirk Broadhurst    16 年前

    q 属于类型 List<Product>

    第一个或最后一个产品将有一个价格。

    q.First().Price
    q.Last().Price
    

    如果你知道只有一个在集合中,你也可以用单一的

    q.Single().Price
    
        7
  •  1
  •   Henk Holterman    16 年前

    var price = p.Price;
    var q = repo.Products().Where(x=>x.Price == price).ToList()
    
        8
  •  0
  •   Paulo Santos    16 年前

    你到底想达到什么目的?

    因为要获得 Price

    var valueOfPrice = q[0].Price;
    
        9
  •  -1
  •   Alexandre Daubricourt    5 年前

    截至2020年

    此助手方法将优雅地检索任何表达式值,而无需“编译hack”:

    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;
    }
    

    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;
        }
    }