What is the lifetime of a delegate created by a lambda in C#?

前端 未结 5 1255
忘掉有多难
忘掉有多难 2020-12-08 04:00

Lambdas are nice, as they offer brevity and locality and an extra form of encapsulation. Instead of having to write functions which are only used once you can use a lambda.<

5条回答
  •  死守一世寂寞
    2020-12-08 04:52

    Based on your question here and your comment to Jon's answer I think you are confusing multiple things. To make sure it is clear:

    • The method that backs the delegate for a given lambda is always the same.
    • The method that backs the delegate for "the same" lambda that appears lexically twice is permitted to be the same, but in practice is not the same in our implementation.
    • The delegate instance that is created for a given lambda might or might not always be the same, depending on how smart the compiler is about caching it.

    So if you have something like:

    for(i = 0; i < 10; ++i)
        M( ()=>{} )
    

    then every time M is called, you get the same instance of the delegate because the compiler is smart and generates

    static void MyAction() {}
    static Action DelegateCache = null;
    
    ...
    for(i = 0; i < 10; ++i)
    {
        if (C.DelegateCache == null) C.DelegateCache = new Action ( C.MyAction )
        M(C.DelegateCache);
    }
    

    If you have

    for(i = 0; i < 10; ++i)
        M( ()=>{this.Bar();} )
    

    then the compiler generates

    void MyAction() { this.Bar(); }
    ...
    for(i = 0; i < 10; ++i)
    {
        M(new Action(this.MyAction));
    }
    

    You get a new delegate every time, with the same method.

    The compiler is permitted to (but in fact does not at this time) generate

    void MyAction() { this.Bar(); }
    Action DelegateCache = null;
    ...
    for(i = 0; i < 10; ++i)
    {
        if (this.DelegateCache == null) this.DelegateCache = new Action ( this.MyAction )
        M(this.DelegateCache);
    }
    

    In that case you would always get the same delegate instance if possible, and every delegate would be backed by the same method.

    If you have

    Action a1 = ()=>{};
    Action a2 = ()=>{};
    

    Then in practice the compiler generates this as

    static void MyAction1() {}
    static void MyAction2() {}
    static Action ActionCache1 = null;
    static Action ActionCache2 = null;
    ...
    if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
    Action a1 = ActionCache1;
    if (ActionCache2 == null) ActionCache2 = new Action(MyAction2);
    Action a2 = ActionCache2;
    

    However the compiler is permitted to detect that the two lambdas are identical and generate

    static void MyAction1() {}
    static Action ActionCache1 = null;
    ...
    if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
    Action a1 = ActionCache1;
    Action a2 = ActionCache1;
    

    Is that now clear?

提交回复
热议问题