cordialgerm
cordialgerm

Reputation: 8503

How to access closed-over local variable in MemberExpression?

I am writing some expression analyzing code that needs to access the value of parameters in an Expression<Action>.

The below code works whenever the parameter is a member or property on the source object, but fails when the member is a close-over local variable. How can I get access to the anonymous type that is closing over the local variable so that I can access the local variable?

Here's the error message:

Test method FluentCache.Test.ClosureTest.Test threw exception: 
System.ArgumentException: Field 'localVariable' defined on type 'Test.ClosureTest+<>c__DisplayClass2' is not a field on the target object which is of type 'Test.ClosureTest'

Here's the simplified code:

[TestMethod]
public void Test()
{
    Func<int, int> myAction = i => i + 1;
    int localVariable = 10;

    int analyzed = (int)GetFirstParameterValue(this, () => myAction(localVariable));

    Assert.AreEqual(localVariable, analyzed);
}

public object GetFirstParameterValue(object source, Expression<Action> expression)
{
    var invocationExpression = expression.Body as InvocationExpression;
    var parameterExpression = invocationExpression.Arguments[0] as MemberExpression;
    var parameterFieldInfo = parameterExpression.Member as FieldInfo;

    //ERROR: This code will fail because the local variable is "wrapped" in a closure anonymous type
    //How do I get access to the anonymous type in order to retrieve the value?
    object fieldValue = parameterFieldInfo.GetValue(source);
    return fieldValue;
}

Upvotes: 2

Views: 242

Answers (1)

Kirk Woll
Kirk Woll

Reputation: 77556

The object containing the value of your field is contained in the Expression property of parameterExpression. Thus change the second to last line of your code to:

object fieldValue = parameterFieldInfo.GetValue(
    ((ConstantExpression)parameterExpression.Expression).Value);

The instance we're passing in is the constant closure type available via parameterExpression.

Here's a .Net fiddle demonstrating the solution.

Upvotes: 1

Related Questions