如何通过表达式树生成的委托调用自己?
Posted
技术标签:
【中文标题】如何通过表达式树生成的委托调用自己?【英文标题】:How do I call myself through the delegate generated by the expression tree? 【发布时间】:2019-06-09 04:31:56 【问题描述】:现在我要把表达式树编译成一个委托来动态生成代码,但是我有一个问题。我必须调用表达式树中的一个方法,这正是尚未动态编译的表达式树委托。我该怎么办?
我想从表达式树生成如下代码:
int i = 0;
Action ac = null;
ac = () =>
//if (i-- > 0) condition
ac();
;
以下代码不起作用,会提示ac is null
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();
【问题讨论】:
它不起作用吗? 如果你想要一个递归委托,声明一个。不要费心尝试制作无名递归委托。 @J. van Langen 我已经编辑了问题 @user2864740 我已经编辑了问题 我在这里找到了:Recursive Methods in Expression Trees。您必须创建两个 lambda 表达式。第一个生成第二个 lambda 并将其存储在一个变量中,然后将该变量作为参数传递给第二个 lambda。 【参考方案1】:表达式的问题是你只能按值传递变量,所以你需要一些技巧来传递引用。你可以这样做:
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();
【讨论】:
以上是关于如何通过表达式树生成的委托调用自己?的主要内容,如果未能解决你的问题,请参考以下文章