Get the final values ​​from the parameters of the lambda expression method

Basically I want to get the parameter values ​​of the called method as follows:

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

Well, you need to expand the expression, find MethodCallExpression , and then look at the arguments. Note that we do not have the value o , so we must assume that the arguments to the method do not rely on this. Also, we still assume that the lambda expression simply relies on the fact that it is a MethodCallExpression ?

EDIT: Well, here is an edited version that evaluates the arguments. However, it is assumed that you are not using the lambda expression parameter in the arguments (this is what new object[1] says - it provides an effective null parameter).

 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<Foo>(o => o.Save(x, "Jimmy", a + b + 5, Math.Sqrt(81))); } static void ShowValues<T>(Expression<Action<T>> 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); } } } 
+17
source share

As John said, you can check if the expression MethodCallExpression

 class Program { static void Main(string[] args) { Program.Do<Controller>(c => c.Save(1, "Jimmy")); } public static void Do<T>(Expression<Action<T>> 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) { } } 
+4
source share

Here is some code that is designed to work with any expression - in the sense that it basically does not assume that you are passing a method expression. However, it is not complete. You will need to fill in the rest.

 public static IEnumerable<object> ExtractConstants<T>( Expression<Action<T>> expression) { return extractConstants(expression); } private static IEnumerable<object> 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(); } 

In the case you mentioned, this already works:

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

For more complex lambda expressions that use other types of expression nodes, you will have to gradually expand the above code. Every time you use it and it throws a NotImplementedException , here is what I do:

  • Open the Clock window in the debugger
  • Look at the expression variable and its type
  • Add the necessary code to handle this type of expression

Over time, the method will become more complete.

+2
source share

My universal answer is below. Hope this helps you and someone else.

 var dict = new Dictionary<string, object>(); 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; } 
+2
source share
  public override IQueryable<Image> FindAll(System.Linq.Expressions.Expression<Func<Image, dynamic>> Id) { dynamic currentType = Id.Parameters[0]; var id = currentType.Type.GUID; var result = (_uniwOfWork as UnitOfWork).uspGetImages(id.ToString()); return FindAll(); } 

use the dynamic keyword.

0
source share

All Articles