Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get reference to parameter inside a Lambda passed as a Func

Tags:

c#

lambda

func

Given the following set of classes:

public class MyClass
{
    public int MyInt { get; set; }
}    

public class ObjectProcessor
{
    public int ProcessObject(MyClass myClass)
    {
        return myClass.MyInt ++;
    } 
}

public class Runner
{
    public void Run()
    {
        var classToPass = new MyClass();

        FuncExecutor.ExecuteAction<MyClass>(x => x.ProcessObject(classToPass));
    }
}

public static class FuncExecutor
{
    public static void ExecuteAction<T>(Expression<Func<ObjectProcessor, int>> expression)
    {
        // var func = expression.Compile(); ... does having an Expression help?

        // How can I get a reference to 'classToPass' at this point?

        // The 'classToPass' Type is known to be 'T', in this case 'MyClass'.
    }
}

From within the ExecuteAction method, how can I get a reference to the classToPass instance that was passed in to ProcessObject?

EDIT: The comments have highlighted the complexity of trying to parse Expression Trees which could vary widely in their composition.

However, in this particular case there are two facts which cut down this variation considerably:

  • ProcessObject will only ever take a single parameter.
  • The parameter type is known in advance.

Code altered to express this.

like image 710
Holf Avatar asked Dec 29 '25 20:12

Holf


1 Answers

To answer very specifically:

public class Runner
{
    public void Run()
    {
        var classToPass = new MyClass();
        classToPass.MyInt = 42;

        FuncExecutor.ExecuteAction(x => x.ProcessObject(classToPass));
    }
}

public class FuncExecutor
{
    public static void ExecuteAction(Expression<Func<ObjectProcessor, int>> expression)
    {
        var lambdaExpression = (LambdaExpression)expression;
        var methodCallExpression = (MethodCallExpression)lambdaExpression.Body;

        var memberExpression = (MemberExpression)methodCallExpression.Arguments[0];
        var constantExpression = (ConstantExpression)memberExpression.Expression;
        var fieldInfo = (FieldInfo)memberExpression.Member;

        var myClassReference = (MyClass) fieldInfo.GetValue(constantExpression.Value);

        Console.WriteLine(myClassReference.MyInt); // prints "42"
    }
}

Please note that when you pass the lambda to the ExecuteAction method, you capture a local variable reference (classToPass). The compiler will generate some code to handle that properly. More precisely, it will generate a type with a single member (a field) of type MyClass to hold the reference and use it from this point. That's why you'll get a MemberExpression in the argument expression list.

Since you can't directly manipulate this generated type, you can't just use the member expression Value property. But you can dynamically invoke the member accessor using the MemberInfo and the target reference (an instance of the compiler generated type).

I would not rely on this code.

You can read more about lambda related compiler generated code here, for example: http://thewalkingdev.blogspot.fr/2012/04/c-lambda-expressions-and-closures.html

like image 135
Romain Verdier Avatar answered Jan 01 '26 09:01

Romain Verdier



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!