Closed. This question needs to be more focused。它当前不接受答案。
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            想改善这个问题吗?更新问题,使其仅通过editing this post专注于一个问题。
                        
                        2年前关闭。
                                                                                            
                
        
当我运行此代码时:

string x = "";
Action<int> myAction = (i) => x += ("A" + i);
myAction = (i) =>
{
    if (i > 0)
    {
        x += ("B" + i);
        myAction += (i2) => x += ("C" + i + i2);
        myAction(i - 1);
    }
};
myAction(3);
Console.WriteLine(x);


打印的内容是:
B3B2B1C30C20C10C31C21C32

谁能给我解释为什么打印出来?

最佳答案

请注意,一旦您这样做:

myAction = ....


您可以忘记先前将myAction设置为的内容;现在已经输给了以太。您可能还已经初始化了Action<int> myAction = null;。关键是要捕获变量myAction-而不是其值。因此,第二个委托中的代码正在调用自身,而不是涉及“ A”的代码。

同样,当您执行myAction += (i2) => x += ("C" + i + i2);时,您将更改所有后续代码的委托。

还要注意,本地函数现在可能是一种更好且更清晰的方式来执行此类操作。



让我们看看实际发生了什么。我们从开始:

myAction = (i) =>
{
    if (i > 0)
    {
        x += ("B" + i);
        myAction += (i2) => x += ("C" + i + i2);
        myAction(i - 1);
    }
};


并调用myAction(3)i>0,因此x变为“ B3”。现在我们做一些复杂的事情-我们结合了两个委托,所以myAction现在是:

myAction = (i) =>
{
    if (i > 0)
    {
        x += ("B" + i);
        myAction += (i2) => x += ("C" + i + i2);
        myAction(i - 1);
    }
} + (i2) => x += ("C" + i + i2);


(这意味着它先运行一个方法,然后再运行另一个方法),并注意第二个委托中的i是上一个调用中的参数i。由于该参数不变,因此我们可以名义上对其进行修复(尽管实际上它是一个捕获上下文字段),并说:

myAction = (i) =>
{
    if (i > 0)
    {
        x += ("B" + i);
        myAction += (i2) => x += ("C" + i + i2);
        myAction(i - 1);
    }
} + (i2) => x += ("C" + 3 + i2);


现在我们调用myAction(i - 1 === 2);。很好-让我们依次执行这两部分;第一部分找到i>0,因此x变为“ B3B2”。现在我们重写myAction,使其变为三倍:

myAction = (i) =>
{
    if (i > 0)
    {
        x += ("B" + i);
        myAction += (i2) => x += ("C" + i + i2);
        myAction(i - 1);
    }
} + (i2) => x += ("C" + 3 + i2)
  + (i2) => x += ("C" + 2 + i2);


(请注意,我已经像以前一样固定了参数的值),然后执行myAction(i - 1)

在执行此操作之前……请记住,我们仍有待执行的(i2) => x += ("C" + 3 + i2);待执行,但稍后会发生(稍后我将其称为“ PendingA”)。由于委托是不可变的,因此我们为委托分配新值不会影响该挂起的执行。

因此:i2=2:再次,myAction(i-1 === 1)使得i>0变为“ B3B2B1”,我们再次更改了委托:

myAction = (i) =>
{
    if (i > 0)
    {
        x += ("B" + i);
        myAction += (i2) => x += ("C" + i + i2);
        myAction(i - 1);
    }
} + (i2) => x += ("C" + 3 + i2)
  + (i2) => x += ("C" + 2 + i2);
  + (i2) => x += ("C" + 1 + i2);


(再次,注意我固定的价值)。我们再次使用x调用它,首先要注意我们有一个待处理的:

    (i2) => x += ("C" + 3 + i2)
  + (i2) => x += ("C" + 2 + i2); // call this PendingB


使用myAction(i-1) === 0以便稍后展开时运行。

第一部分没有做任何事情,但是我们确实有三个后缀可以与i2===1一起运行。因此我们得到(依次应用)“ B3B2B1C30C20C10”。至此,我们已经完成了工作-我们已经达到了栈底。现在我们需要展开!我们有一个待办事项双脚跑。展开时,“ PendingB”首先出现,这使i2===0变为“ B3B2B1C30C20C10C31C21”;然后“ PendingA”给我们“ B3B2B1C30C20C10C31C21C32”

关于c# - 引用并添加到自身的C#委托(delegate),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44312394/

10-08 22:31