Search code examples
c#genericslambdasystem.reflection

How can i get the parameter values of an anonymous method passed as a func?


I am calling methods on a remote system. The remote system implements an interface that both systems have a copy of (via shared nuget repository). At the moment i am sending the requests like this:

var oldRequest = new FooRequest("GetEmployeeById", new object[] { "myPartner", 42, DateTime.Now.AddDays(-1) });

Here is the interface:

public class FooResponse<T> { }

public interface IFooController
{
    FooResponse<string> GetEmployeeById(string partnerName, int employeeId, DateTime? ifModifiedSince);
}

As you can image, sometimes programmers passes arguments in the wrong order to the array in the constructor, and things start to fail. To resolve this I have created the following code to have intellisense support when creating the FooRequest:

public static FooRequest Create<T>(Func<FooResponse<T>> func)
{
    return new FooRequest(null, null); // Here goes some magic reflection stuff instead of null.
}

It is now possible to create a FooRequest like this:

public static IFooController iFooController => (IFooController)new object();
public static FooRequest CreateRequest<T>(Func<FooResponse<T>> func)
{
    return FooRequest.Create(func);
}

var newRequest = CreateRequest(() => iFooController.GetEmployeeById("myPartner", 42, DateTime.Now.AddDays(-1)));

My question then is: How will i be able to get the name of the method and the value of the parameters in the FooRequest.Create-method?

I have exhausted both my reflection and google-skills trying to find the values, but no luck so far.

Complete compiling code can be found here if someone wants to give it a shot: http://ideone.com/ovWseI


Solution

  • Here is a sketch of how you can do this with expressions:

    public class Test {
        public static IFooController iFooController => (IFooController) new object();
    
        public static FooRequest CreateRequest<T>(Expression<Func<FooResponse<T>>> func) {
            return FooRequest.Create(func);
        }
    
        public static void Main() {
            var newRequest = CreateRequest(() => iFooController.GetEmployeeById("myPartner", 42, DateTime.Now.AddDays(-1)));
            Console.ReadKey();
        }
    }
    
    public class FooRequest {
        public static FooRequest Create<T>(Expression<Func<FooResponse<T>>> func) {
            var call = (MethodCallExpression) func.Body;
            var arguments = new List<object>();
            foreach (var arg in call.Arguments) {
                var constant = arg as ConstantExpression;
                if (constant != null) {
                    arguments.Add(constant.Value);
                }
                else {
                    var evaled = Expression.Lambda(arg).Compile().DynamicInvoke();
                    arguments.Add(evaled);
                }
            }
            return new FooRequest(call.Method.Name, arguments.ToArray());
        }
    
        public FooRequest(string function, object[] data = null) {
            //SendRequestToServiceBus(function, data);
            Console.Write($"Function name: {function}");
        }
    }
    
    public class FooResponse<T> {
    }
    
    public interface IFooController {
        FooResponse<string> GetEmployeeById(string partnerName, int employeeId, DateTime? ifModifiedSince);
    }