Search code examples
c#delegatesanonymous-methodsfunc

How to determine anonymous function parameters in c#?


Given the following code,

    public T Execute<T>(Func<T> methodParam)
    {
        return methodParam ();
    }

    public void CallMethodsAnonymously<T>()
    {
        T result =  Execute(() => _service.SomeMethod1());
        T result1 = Execute(() => _service.SomeMethod2(someParm1));
        T result2 = Execute(() => _service.SomeMethod3( someParm1, someParm2));
    }

From the Execute method, is it possible to inspect “methodParam” and extract or determine the number of parameters within the anonymous function body? For example is it possible to determine the values of someParam1 and someParam2 from within the Execute method?


Solution

  • You can do it using the Expression API:

    public static T Execute<T>(Expression<Func<T>> methodParam)
    {
        var methodCallExpression = methodParam.Body as MethodCallExpression;
        var method = methodCallExpression.Method;
        var parameters = method.GetParameters();
    
        return methodParam.Compile()();
    }
    

    The parameters variable will be an array of ParameterInfo objects which will contain the information you need. Finally, the Compile method actually converts the Expression to an executable delegate. The C# compiler also allows you to call this method with the regular conventions of calling methods that take delegates, with the standard lambdas/anonymous methods.

    EDIT:

    I also just noticed that you wanted a way to get the actual value of the someParam1 and someParam2. Here's how you can do that:

    private static object GetValue(Expression expression)
    {
        var constantExpression = expression as ConstantExpression;
        if (constantExpression != null)
        {
            return constantExpression.Value;
        }
    
        var objectMember = Expression.Convert(expression, typeof(object));
        var getterLambda = Expression.Lambda<Func<object>>(objectMember);
        var getter = getterLambda.Compile();
        return getter();
    }
    
    
    private static object[] GetParameterValues(LambdaExpression expression)
    {
        var methodCallExpression = expression.Body as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return methodCallExpression.Arguments.Select(GetValue).ToArray();
        }
    
        return null;
    }
    

    So now in your execute method, if you do this:

    public static T Execute<T>(Expression<Func<T>> methodParam)
    {
        var methodCallExpression = methodParam.Body as MethodCallExpression;
        var method = methodCallExpression.Method;
        var parameters = method.GetParameters();
    
        var values = GetParameterValues(methodParam);
        return methodParam.Compile()();
    }
    

    then the values will be an object[] with all the actual values that were passed in.