Specify a parameter to express the general method

I would like to indicate a parameter that a method can take without specifying general arguments for creating the MethodInfo of this method.

For example, I would like to write code like this:

interface IService { object AMethod(int p1, int p2); } IThingy<IService>() thingy; thingy.Add(svc => svc.AMethod); 

The nearest options that I can produce are as follows:

 interface IThingy<TService> { void Add1<T0, T1, TResult>(Expression<Func<TService, Func<T0, T1, TResult>>> expression); void Add2(Expression<Func<TService, Func<int, int, object>>> expression); void Add3(Expression<Action<TService>> expression); } thingy.Add1<int, int, object>(svc => svc.AMethod); thingy.Add2(svc => svc.AMethod); thingy.Add3(svc => svc.AMethod(0, 0)); 

Add1 implies a lot of Func overloads, which I'm fine with, but cannot be called without specifying common parameters.

Add2 does not require common parameters, but implies a specific overload for each parameter signature.

Add3 requires a method call, including fake parameters.

FYI, I will process the expression to get the MethodInfo of this method as follows:

 MemberInfo GetMemberFromExpression<T>(Expression<ActionT>> expression) { return ((MethodCallExpression)expression.Body).Method } GetMemberFromExpression(svc => svc.AMethod(0, 0)); 
+6
source share
1 answer

Passing methods to expressions with their called values

You can use the GetMemberFromExpression method as it is, and then simply remove the Generic parameter. As below:

 static void Main(string[] args) { var memberInfo1 = GetMemberFromExpression(() => Method1(10, 20)); var memberInfo2 = GetMemberFromExpression(() => Method2()); var memberInfo3 = GetMemberFromExpression(() => Method3("string", 15, DateTime.Now)); Console.WriteLine(memberInfo1.Name); Console.WriteLine(memberInfo2.Name); Console.WriteLine(memberInfo3.Name); Console.Read(); } public static MemberInfo GetMemberFromExpression(Expression<Action> expression) { return ((MethodCallExpression)expression.Body).Method; } public static object Method1(int p1, int p2) { return p1 + p2; } public static void Method2() { // No return } public static double Method3(string p1, int p2, DateTime p3) { return 10d; } 

You will see that GetMemberFromExpression will return MethodInfo any method you pass, regardless of the type or type of the parameter and the type of return.


Ignore overloads, call by name and name

If you're not worried about overloads, you can probably use simple reflection instead of creating expressions. A nameof operator in C # 6 would be a better approach than passing a name as a string (compile time checking).

 public static MemberInfo GetMemberInfo(Type type, string methodName) { return type.GetMethod(methodName); } 

Please note: there are no validation checks in this method, just to show the concept.

The above method will work for any instance or static methods. Just pass an instance type type / or a static class type and a method name as follows:

 MyClass cl = new MyClass(); var methodInfo1 = GetMemberInfo(cl.GetType(), "AMethod"); var methodInfo2 = GetMemberInfo(typeof(MyClass), "AStaticMethod"); 

Here's MyClass using methods:

 class MyClass { public void AMethod(int a, int b) { // instance method } public static bool AStaticMethod(bool a, bool b) { return a & b; // static method } } 

This way you are not passing any parameters, because you are just studying the definition and not calling.


Using expressions with types rather than values

Here is the third option. So you have:

  • Check compilation time,
  • No need to pass valuable ("fake") parameters,
  • Only the required parameter types are required (which ensures that overloaded methods will work).

Create a class that serves Action and Func overloads:

 public class Method { public static MethodInfo GetInfo<TReturn>(Func<TReturn> method) { return method.Method; } public static MethodInfo GetInfo<TP1, TReturn>(Func<TP1, TReturn> method) { return method.Method; } public static MethodInfo GetInfo<TP1, TP2, TReturn>(Func<TP1, TP2, TReturn> method) { return method.Method; } //... Continue with some more Func overloads public static MethodInfo GetInfo(Action method) { return method.Method; } public static MethodInfo GetInfo<TP1>(Action<TP1> method) { return method.Method; } public static MethodInfo GetInfo<TP1, TP2>(Action<TP1, TP2> method) { return method.Method; } //... Continue with some more Action overloads } 

Now you can simply get your MethodInfo as follows:

 var methodInfo1 = Method.GetInfo<int, int>(cl.AMethod); var methodInfo2 = Method.GetInfo<bool, bool, bool>(MyClass.AStaticMethod); 

Yes, you need to create a bunch of overloads in the Method class for Action and Func , but that will not be correct, and you will do the same with .NET Action and Func to serve all overloads.

+1
source

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


All Articles