Access the value of a member expression

前端 未结 9 2018
滥情空心
滥情空心 2020-12-04 08:33

If i have a product.

var p = new Product { Price = 30 };

and i have the following linq query.

var q = repo.Products().Where         


        
相关标签:
9条回答
  • 2020-12-04 08:53
     MemberExpression right = (MemberExpression)((BinaryExpression)p.Body).Right;
     Expression.Lambda(right).Compile().DynamicInvoke();
    
    0 讨论(0)
  • 2020-12-04 08:53

    If you had a class:

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

    and an instance of the object:

    var myItem = new Item { Id = 7 };
    

    You can get the value of Id using an Expression using the following code:

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

    myValue will contain "7"

    0 讨论(0)
  • 2020-12-04 08:57

    Can you use the following:

    var price = p.Price;
    var q = repo.Products().Where(x=>x.Price == price).ToList()
    
    0 讨论(0)
  • 2020-12-04 08:59

    As of 2020

    This helper method will gracefully retrieve any expression value, without "compiling 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 class :

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-04 09:01

    q is of type List<Product>. The List doesn't have a Price property - only the individual Products.

    The first or last Product will have a price.

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

    If you know there's only one in the collection you can also flatten it using Single

    q.Single().Price
    
    0 讨论(0)
  • 2020-12-04 09:08

    You can compile and invoke a lambda expression whose body is the member access:

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

    Local evaluation is a common technique when parsing expression trees. LINQ to SQL does this exact thing in quite a few places.

    0 讨论(0)
提交回复
热议问题