Reputation: 9248
I am trying to generate expression like (Foo foo) => () => foo.Bar()
, and then run the outer lambda providing the Foo
instance, so that returned value would be a closure which statically calls Foo.Bar
, to avoid implicit exception catching introduced by the dynamic call.
However, calling the outer expression fails with exception "variable 'foo' of type 'ConsoleApp2.Foo' referenced from scope '', but it is not defined".
Am I making some mistake or there is some conceptual reason preventing it?
The minimal full code:
using System;
using System.Linq.Expressions;
namespace ConsoleApp2 {
class Program {
static void Main(string[] args)
{
// supposed to be "(Foo foo) => () => foo.Bar()",
// inspecting `expr` in debugger seems to agree
var expr = Expression.Lambda(
Expression.Lambda(
Expression.Call(Expression.Variable(typeof(Foo), "foo"), typeof(Foo).GetMethod("Bar"))),
new[] { Expression.Variable(typeof(Foo), "foo") });
// here exception "variable 'foo' of type 'ConsoleApp2.Foo' referenced from scope '', but it is not defined" is thrown
var res = (Action)expr.Compile().DynamicInvoke(new Foo());
res();
}
}
class Foo
{
public void Bar()
{
Console.WriteLine("Bar");
}
}
}
Upvotes: 4
Views: 363
Reputation: 12878
I would imagine it is because you need to reference the same variable, this seems to resolve your problem.
var foo = Expression.Variable(typeof(Foo), "foo");
var expr = Expression.Lambda(
Expression.Lambda(
Expression.Call(foo, typeof(Foo).GetMethod("Bar"))),
new[] { foo });
Upvotes: 4
Reputation: 5543
You need to make sure that the variable expressions in the lambda expression reference the same instance.
This code runs just fine, and seems to give the expected result.
void Main()
{
var var = Expression.Variable(typeof(Foo), "foo");
var expr = Expression.Lambda(
Expression.Lambda(
Expression.Call(var, typeof(Foo).GetMethod("Bar"))), new[] { var });
var res = (Action)expr.Compile().DynamicInvoke(new Foo());
res();
}
class Foo
{
public void Bar()
{
Console.WriteLine("Bar");
}
}
Upvotes: 4