Method for passing unknown arguments / Type of return as a parameter in C #

There is a similar question here:

Skip method as parameter using C #

It is assumed that you know the arguments of the method and the type of the return value. I would like to do something completely different. I am looking to create a version of System.Reflection.GetMethod (string) that instead takes a lambda function - so instead:

MethodInfo methodInfo = typeof(MyClass).GetMethod("AddThing"); 

I could use a more compiled file:

 MethodInfo methodInfo = ReflectionHelper.GetMethod<MyClass>(mc => mc.AddThing); 

So, if the ReflectionHelper knew the count argument and the return type in advance, the answer would be simple - for example, if it had no arguments and the return string:

 public static MethodInfo GetMethod<T, TReturn>(Expression<Func<T, Func<TArg, TReturn>>> expr) { return ((MethodCallExpression)expr.Body).Method; } 

Except that I don't know the count / return type argument in advance, and I would like to avoid spam with 20 overloads that cover most, but not all cases.

So how do I do this?

+4
source share
2 answers

You did not specify a method in lambda mc => mc.AddThing - you specified a group of methods.

What you can do is write a method call in the expression, although it will never be executed, so the parameters just have to specify the required overload.

So, to use it, you have to write:

 MethodInfo mi = GetMethod<MyClass>( mc => mc.AddThing( null ) ); 

Then the expression might just be Action , not Func :

 public static MethodInfo<T>( Expression<Action<T>> expr ) { return ( ( MethodCallExpression ) x.Body ).Method; } 

As always when checking expressions, this is prone to runtime errors if the lambda does not match the expected form, but it is a step in the right direction to get rid of the β€œmagic” lines.

+3
source

The workaround I'm using now, which I will call the "spam approach", is ugly but functional in a limited set of scripts:

 public class ReflectionHelper<T> { public MethodInfo GetMethod<TA1>(Expression<Func<T, Func<TA1>>> expr) { return ((MethodCallExpression)expr.Body).Method; } public MethodInfo GetMethod<TA1, TA2>(Expression<Func<T, Action<TA1, TA2>>> expr) { return ((MethodCallExpression)expr.Body).Method; } public MethodInfo GetMethod<TA1, TA2, TA3>(Expression<Func<T, Action<TA1, TA2, TA3>>> expr) { return ((MethodCallExpression)expr.Body).Method; } . . . // And more } 

And it goes on to indicate a long list of potential actions and Funcs with various arguments. This allows me to use it like:

 (new ReflectionHelper<MyClass>()).GetMethod<string>(mc => mc.SaySomething).Invoke("Hi"); 

So this is close-ish - I get just a method call by name, and I don't avoid passing fake arguments to do this, but I still realized what the types of its arguments are - more complicated than I had hoped. In a situation with multiple method overloads with the same name, passing argument types, however, limits the list of methods to one specific overload.

Anyway, I would be interested in something even simpler that the method can just take, as in my Question. This would be undefined in method overload situations, but is also the standard .GetMethod (string).

0
source

All Articles