【问题标题】:How do I get a value of a reference type in an Expression?如何在表达式中获取引用类型的值?
【发布时间】:2010-03-23 20:21:54
【问题描述】:

我有这个方法:

public void DoSomething<T>(Expression<Func<T, object>> method)
{
}

如果这个方法是这样调用的:

DoSomething(c => c.SomeMethod(new TestObject()));

...如何获取传递给 SomeMethod() 的参数值?

如果参数是值类型,则有效:

var methodCall = (MethodCallExpression)method.Body;
var parameterValue = ((ConstantExpression)methodCall.Arguments[0]).Value;

但是,当我传入一个引用类型时,methodCall.Arguments[0] 是一个 MemberExpression,我似乎无法弄清楚如何编写代码来从中获取值。

【问题讨论】:

  • 你必须能够做到,Rhino Mocks 做到了。

标签: c# .net lambda


【解决方案1】:

这是答案(灵感来自 Akash 的回答):

LambdaExpression lambda = Expression.Lambda(methodCall.Arguments[0]);
var compiledExpression = lambda.Compile();
return compiledExpression.DynamicInvoke();

【讨论】:

  • 请注意,这是表达式在那个时间点的值。您还应该考虑传入原始表达式的参数,以防它们在子表达式中使用。
  • 没关系,这是一个测试断言辅助方法,所以我只需要知道那个时间点的值。
【解决方案2】:

您必须手动评估成员表达式,MemberExpression 包含“Expression”,它是指定成员的容器对象,为此,您可以创建参数的 Lamda 并编译并执行它。

LamdaExpression l = Expression.Lambda(methodCall.Arguments[0]);
var c = l.Compile();
var v = c.Invoke();

所以无论你传递什么,你都会在“v”变量中得到它。

【讨论】:

    【解决方案3】:

    这实际上不是值类型或引用类型的问题,而是常量表达式或非常量表达式的问题。我敢肯定,如果你打电话,你现有的代码会失败

    DoSomething(c => c.SomeMethod(DateTime.Now));
    

    也是。

    基本上,方法的参数只是一个表达式。这不是一个值。您可能会编译该表达式,然后执行它以获取该时间点的值,但重要的是要了解表达式本身并不是一个值。在常量表达式的情况下,这很容易,但以DateTime.Now 为例,根据定义,表达式的评估值会随时间变化:)

    你想用这个论点做什么?这里的大局是什么?

    【讨论】:

    • @Downvoters:你有没有机会真正留下一些你不喜欢我的回答的迹象?没有 cmets 的 2 次downvotes 有点奇怪......
    • 也许没什么私人的,我猜@akasha 的回答更接近于给 OP 他想要的东西。可能反对者已经对@akahsa 投了赞成票,并认为它应该比你的答案高。我会给你们一个+1的好业力。
    【解决方案4】:

    首先,乔恩说了什么。

    没有可以掌握的值,它只是表达式。可能感兴趣的是NewExpression,它有一个Constructor 属性;此属性包含反射构造函数,如果您编译表达式并运行生成的委托,将调用该构造函数。您可以手动调用该构造函数并获取用户打算实例化的实例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 2016-11-22
      • 1970-01-01
      • 2017-01-24
      相关资源
      最近更新 更多