现在,我将把表达式树编译成一个委托以动态生成代码,但是我遇到了问题。我必须在表达式树中调用一个方法,该方法恰好是尚未动态编译的表达式树委托。我该怎么办?
我想从表达式树生成以下代码:
int i = 0;
Action ac = null;
ac = () =>
{
//if (i-- > 0) condition
ac();
};
以下代码不起作用,将提示ac为空
static Action ac = Build();
static Action Build()
{
return Expression.Lambda<Action>(
Expression.Call(
Expression.Constant(ac), //throw ac is null
typeof(Action).GetType().GetMethod("Invoke")
)
).Compile();
}
答案 0 :(得分:0)
表达式的问题是只能按值传递变量,因此需要一些技巧来传递引用。您可以这样做:
Action<Node> ac = null;
Func<Action<Node>> getAction = () => ac;
然后构建这样的表达式:
ac = () =>
{
//if (i-- > 0) condition
getAction()();
};
另一个选择是将动作包装在某些对象中
Wrapper<Action> = new Wrapper();
ac = () =>
{
//if (i-- > 0) condition
wrapper.Value();
};
wrapper.Value = ac;
这是示例代码:
class Wrapper<T>
{
public T Value { get; set; }
}
static void Main(string[] args)
{
Node root = new Node
{
Name = "First",
Next = new Node {Name = "Second"}
};
var method = Build();
method(root);
}
class Node
{
public string Name { get; set; }
public Node Next { get; set; }
}
static Action<Node> Build()
{
var wrapper = new Wrapper<Action<Node>>();
var param = Expression.Parameter(typeof(Node), "node");
var expr = Expression.Lambda<Action<Node>>(
Expression.Block(
// Console.WriteLine("Node name: {0}", node.Name);
Expression.Call(
typeof(Console),
"WriteLine",
Type.EmptyTypes,
Expression.Constant("Node name: {0}"),
Expression.Property(param, "Name")
),
// if (node.Next != null) wrapper.Value(node.Next)
Expression.IfThen(
Expression.ReferenceNotEqual(Expression.Property(param, "Next"), Expression.Constant(null)),
// wrapper.Value(node.Next)
Expression.Invoke(
// wrapper.Value
Expression.Property(Expression.Constant(wrapper), "Value"),
// node.Next
Expression.Property(param, "Next")
)
)
),
param
);
return wrapper.Value = expr.Compile();
}