Problem with Expression.Lambda () parameter

Update: it works, I was stupid: (

I have the following extension method

public static string ExtMethod(this object self, object myparameter); 

at runtime, this is called any number of ways, I think these are all possibilities:

 Expression<Func<T, string>> expr = x => x.property.ExtMethod(5); Expression<Func<T, string>> expr = x => x.property.ExtMethod(new object()); Expression<Func<T, string>> expr = x => x.property.ExtMethod(someMethod()); Expression<Func<T, string>> expr = x => x.property.ExtMethod(x.someMethod()); Expression<Func<T, string>> expr = x => x.property.ExtMethod(x.OtherProperty); 

what I need to do is evaluate " myparameter ", given " expr " and " T "

due to two cases where x used in myparameter , I thought I needed to create a form delegate:

 Expression<Func<T, object>> expr = x => [myparameter expression here] 

I thought this would work:

 var extMethodExpr = expr.Body as MethodCallExpression; var myparameterExpr = extMethodExpr.Arguments[1]; var myparam = Expression.Lambda(myparameterExpr, expr.Parameters).Compile().Invoke(someT) 

but for expressions that do not include x , I get TargetParameterCountException : (

in these cases, if I:

 var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT) 

It works great.

How to solve this?

thanks

+2
source share
2 answers

OK got to the end; in line:

 var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT); 

If you did not try to pass in someT , this will work for those expressions that do not include x in the argument; for those who do this, you need to tell lambda to include the parameter (the same from the original lambda) - simply:

 var myparam = Expression.Lambda(myparameterExpr, outerLambda.Parameters[0]).Compile().Invoke(someT); 

Here is some working code that evaluates the internal parameter (given the instance of the argument type); note that I use the parameter even if it does not include x - otherwise, what would it do with the instance?

 using System; using System.Linq.Expressions; using System.Reflection; class Foo { public string Bar {get;set;} public int someMethod() { return 4; } public int OtherProperty { get { return 3; } } } static class Program { static int someMethod() { return 3; } static void Main() { Foo foo = new Foo(); Test<Foo>(x => x.Bar.ExtMethod(5), foo); Test<Foo>(x => x.Bar.ExtMethod(new object()), foo); Test<Foo>(x => x.Bar.ExtMethod(someMethod()), foo); Test<Foo>(x => x.Bar.ExtMethod(x.someMethod()), foo); Test<Foo>(x => x.Bar.ExtMethod(x.OtherProperty), foo); } static void Test<T>(Expression<Func<T, string>> expr, T instance) { if (expr.Body.NodeType != ExpressionType.Call) { throw new InvalidOperationException("Call expected"); } var call = ((MethodCallExpression)expr.Body); if (call.Method != typeof(Program).GetMethod( "ExtMethod", BindingFlags.Static | BindingFlags.NonPublic)) { throw new InvalidOperationException("ExtMethod expected"); } // we know that ExtMethod has 2 args; pick myParameter (the 2nd); // then build an expression over arg, re-using our outer param var newLambda = Expression.Lambda<Func<T, object>>( call.Arguments[1], expr.Parameters[0]); // evaluate it and show the argument value object value = newLambda.Compile()(instance); Console.WriteLine(value); } static string ExtMethod(this object self, object myParameter) { return self.ToString(); } } 
+6
source

What if you check expr.Parameters.Count and if it is 0, is called without parameters?

0
source

Source: https://habr.com/ru/post/1497845/


All Articles