簡體   English   中英

如何通過表達式樹生成的委托調用自己?

[英]How do I call myself through the delegate generated by the expression tree?

現在我要將表達式樹編譯成委托以動態生成代碼,但是我遇到了問題。 我必須在表達式樹中調用一個方法,它正是尚未動態編譯的表達式樹委托。 我該怎么辦?

我想從表達式樹生成以下代碼:

int i = 0;
Action ac = null;

ac = () =>
{
    //if (i-- > 0)  condition
        ac();
};

以下代碼不起作用,並且提示ac為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();
}

表達式問題是你只能按值傳遞變量,所以你需要一些技巧來傳遞引用。 你可以這樣做:

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();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM