成员表达式的值

如果我有产品。

var p = new Product { Price = 30 };

我有以下linq查询。

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

干杯。

Schotime asked 2019-10-08T23:37:54Z
8个解决方案
96 votes

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

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

Bryan Watts answered 2019-10-08T23:38:11Z
28 votes
 MemberExpression right = (MemberExpression)((BinaryExpression)p.Body).Right;
 Expression.Lambda(right).Compile().DynamicInvoke();
Glennular answered 2019-10-08T23:38:27Z
24 votes

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

Marc Gravell answered 2019-10-08T23:38:59Z
1 votes

q的类型为List<Product>。该列表没有价格属性-仅单个产品。

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

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

如果您知道集合中只有一个,则也可以使用Single展平它

q.Single().Price
Kirk Broadhurst answered 2019-10-08T23:39:37Z
1 votes

您可以使用以下内容:

var price = p.Price;
var q = repo.Products().Where(x=>x.Price == price).ToList()
Henk Holterman answered 2019-10-08T23:40:02Z
1 votes

使用Compile()有几个缺点:

  • Compile()速度很慢。 即使是小的表达片段,也可能需要花费几毫秒的时间才能完成。 但是,Expressions调用之后是超快速的,对于简单的算术表达式或成员访问而言,它仅花费几纳秒的时间。
  • Compile()将生成(发射)MSIL代码。 听起来似乎很完美(并解释了出色的执行速度),但问题是:该代码占用了内存,即使GC收集了委托引用,该代码也无法在应用程序完成之前释放!

可以完全避免Compile()来避免这些问题,也可以缓存已编译的委托以重新使用它们。 我的这个小图书馆提供了Expressions的解释以及缓存的编译,其中,表达式的所有常量和闭包都自动被其他参数替换,然后将其重新插入到闭包中,并返回给用户。 这两个过程都经过了严格的测试,并在生产中使用,它们都有各自的优缺点,但比2560879572359359316482快100倍以上-并且避免了内存泄漏!

Fabian Heimbürger answered 2019-10-08T23:40:49Z
0 votes

您到底想完成什么?

因为要访问Price的值,所以必须执行以下操作:

var valueOfPrice = q[0].Price;
Paulo Santos answered 2019-10-08T23:41:21Z
0 votes

如果您上过课:

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 value = propInfo.GetValue(myItem, null);

值将包含“ 7”

t_warsop answered 2019-10-08T23:42:06Z
translate from https://stackoverflow.com:/questions/2616638/access-the-value-of-a-member-expression