Caster Troy
Caster Troy

Reputation: 2866

Expression API throws exception: variable 'x' of type 'x' referenced from scope '', but it is not defined

public class Program
{
    private static void Main()
    {
        ContrivedComparer.Compare<Person>(person => person.Name == "Calvin");
    }
}

public class Person
{
    public string Name { get; set; }
}

public class ContrivedComparer
{
    // this likely looks highly ill-advised out of context but this is contrived.
    public static readonly object comparatePerson = new Person { Name = "Ted" };

    public static void Compare<TComparate>(Expression<Func<TComparate, bool>> predicate) 
    {
        if (predicate.Compile()((TComparate)comparatePerson)) return;

        var expression = (BinaryExpression)predicate.Body;

        var actual = Expression.Lambda(expression.Left).Compile().DynamicInvoke();
        var expected = Expression.Lambda(expression.Right).Compile().DynamicInvoke();
    }
}

I expect actual to have the same value as the left operand and for expected to have the same value as the the right operand.

However, this code throws an InvalidOperationException with the following message:

variable 'person' of type 'Person' referenced from scope '', but it is not defined.

How can I resolve this exception?

Upvotes: 0

Views: 519

Answers (1)

Servy
Servy

Reputation: 203829

You aren't passing the parameter to the lambda that you're creating the second time, the way that you are the first time. You need to indicate that there is a parameter when constructing the lambda and pass in the value when invoking it.

public static void Compare<TComparate>(Expression<Func<TComparate, bool>> predicate)
{
    if (predicate.Compile()((TComparate)comparatePerson)) return;

    var expression = (BinaryExpression)predicate.Body;

    var actual = Expression.Lambda(expression.Left, predicate.Parameters)
        .Compile().DynamicInvoke(comparatePerson);
    var expected = Expression.Lambda(expression.Right, predicate.Parameters)
        .Compile().DynamicInvoke(comparatePerson);
}

Upvotes: 3

Related Questions