从lambda表达式方法参数中获取结束值

基本上我想得到一个被调用方法的参数值,如下所示:

var x = 1; var a = 2; var b = 3; Do(o => o.Save(x, "Jimmy", a+b+5, Math.Sqrt(81))); public static void Do(Expression<Action> expression) where T : Controller { // get the values 1,Jimmy,10,9 here } 

好吧,你需要钻进表达式,找到MethodCallExpression ,然后查看它的参数。 请注意,我们没有o的值,所以我们必须假设方法的参数不依赖于它。 另外我们还假设lambda表达式只依赖于它是一个MethodCallExpression

编辑:好的,这是一个编辑版本,用于评估参数。 但是,它假设你并没有真正在参数中使用lambda表达式参数(这是new object[1]的意思 – 它有效地提供了一个null参数)。

 using System; using System.Linq.Expressions; class Foo { public void Save(int x, string y, int z, double d) { } } class Program { static void Main() { var x = 1; var a = 2; var b = 3; ShowValues(o => o.Save(x, "Jimmy", a + b + 5, Math.Sqrt(81))); } static void ShowValues(Expression> expression) { var call = expression.Body as MethodCallExpression; if (call == null) { throw new ArgumentException("Not a method call"); } foreach (Expression argument in call.Arguments) { LambdaExpression lambda = Expression.Lambda(argument, expression.Parameters); Delegate d = lambda.Compile(); object value = d.DynamicInvoke(new object[1]); Console.WriteLine("Got value: {0}", value); } } } 

正如Jon所说,您可以检查表达式是否为MethodCallExpression

 class Program { static void Main(string[] args) { Program.Do(c => c.Save(1, "Jimmy")); } public static void Do(Expression> expression) where T : Controller { var body = expression.Body as MethodCallExpression; if (body != null) { foreach (var argument in body.Arguments) { var constant = argument as ConstantExpression; if (constant != null) { Console.WriteLine(constant.Value); } } } } } public class Controller { public void Save(int id, string name) { } } 

下面是一些设计用于处理任何表达式的代码 – 从某种意义上说,它没有从根本上假设您传入的是方法调用表达式。 但是,它并不完整。 你将不得不填写其余的。

 public static IEnumerable ExtractConstants( Expression> expression) { return extractConstants(expression); } private static IEnumerable extractConstants(Expression expression) { if (expression == null) yield break; if (expression is ConstantExpression) yield return ((ConstantExpression) expression).Value; else if (expression is LambdaExpression) foreach (var constant in extractConstants( ((LambdaExpression) expression).Body)) yield return constant; else if (expression is UnaryExpression) foreach (var constant in extractConstants( ((UnaryExpression) expression).Operand)) yield return constant; else if (expression is MethodCallExpression) { foreach (var arg in ((MethodCallExpression) expression).Arguments) foreach (var constant in extractConstants(arg)) yield return constant; foreach (var constant in extractConstants( ((MethodCallExpression) expression).Object)) yield return constant; } else throw new NotImplementedException(); } 

对于您提到的情况,这已经有效:

 // Prints: // Jimmy (System.String) // 1 (System.Int32) foreach (var constant in Ext.ExtractConstants( str => Console.WriteLine("Jimmy", 1))) Console.WriteLine("{0} ({1})", constant.ToString(), constant.GetType().FullName); 

对于使用其他类型的表达式节点的更复杂的lambda表达式,您必须逐步扩展上面的代码。 每次使用它并抛出NotImplementedException ,我都会这样做:

  • 在调试器中打开Watch窗口
  • 查看expression变量及其类型
  • 添加必要的代码来处理该表达式类型

随着时间的推移,该方法将变得越来越完整。

我的普遍答案如下。 我希望它会帮助你和其他人。

 var dict = new Dictionary(); var parameterExpressions = methodCallExpr.Arguments; foreach (var param in method.GetParameters()) { var parameterExpression = parameterExpressions[counter]; var paramValueAccessor = Expression.Lambda(parameterExpression); var paramValue = paramValueAccessor.Compile().DynamicInvoke(); dict[param.Name] = paramValue; } 
  public override IQueryable FindAll(System.Linq.Expressions.Expression> Id) { dynamic currentType = Id.Parameters[0]; var id = currentType.Type.GUID; var result = (_uniwOfWork as UnitOfWork).uspGetImages(id.ToString()); return FindAll(); } 

使用关键字动态。