输出变量和嵌套的 lambda

Out variables and nested lambdas

编码只是为了找点乐趣,让我的头脑了解匿名方法等。我有一个 class,其主要目的是 运行 循环中的 lambda。 lambda 有一个输出参数(exit),它被传递回 class。现在我可以按照下面的代码嵌套它们,其中 l2 在 l1 的 lambda 中声明。

            int outer = 0;

            Loop l1 = new Loop().Infinite((out bool outerExit) =>
            {
                int inner = 0;
                outer++;

                Loop l2 = new Loop().Infinite((out bool innerExit) =>
                {
                    inner++;
                    Debug.WriteLine($"{outer}-{inner}");
                    innerExit = inner >= 3;
                    outerExit = inner >= 3;
                });

                //outerExit = outer >= 3;
            });

            Assert.Equal(3, outer);

然而,这会在我为 outerExit 赋值的 l2 lambda 中产生错误。

Error CS1628 Cannot use ref, out, or in parameter 'outerExit' inside an anonymous method, lambda expression, query expression, or local function

想法是在满足特定条件时从内部循环中退出两个循环。

对于那些感兴趣的人。

public class Loop
    {
        //this is a delegate TYPE!!! that matches our function
        public delegate void ExitableAction<T1>(out T1 a);

        //in thiscase it is a bool
        protected ExitableAction<bool> action;

        protected LoopType type;

        public Loop Infinite(ExitableAction<bool> actn)
        {
            action = actn;
            type = LoopType.Infinite;

            Start();

            return this;
        }

        protected void Start()
        {
            bool exit = false;

            while(!exit)
            {
                action.Invoke(out exit);
            }
        }
    }

关于为什么你不能使用ref/out参数,参见this post

您似乎想重新创建一个具有“中断”功能的“循环”语句。您可以使用另一个 Action<bool> 委托代替 out 参数来实现 break 语句。

public class Loop
{

    protected Action<Action<bool>> action;

    public Loop Infinite(Action<Action<bool>> actn)
    {
        action = actn;

        Start();

        return this;
    }

    protected void Start()
    {
        bool exit = false;

        while (!exit)
        {
            // passes the Action<bool> that assigns the given bool to exit
            action((b) => exit = b); 
        }
    }
}
int outer = 0;

Loop l1 = new Loop().Infinite(setOuterExit =>
{
    int inner = 0;
    outer++;

    Loop l2 = new Loop().Infinite(setInnerExit =>
    {
        inner++;
        Console.WriteLine($"{outer}-{inner}");
        setInnerExit(inner >= 3);
        setOuterExit(inner >= 3);
    });

    setOuterExit(outer >= 3);
});

这给出了最终的 outer 值 3。但是如果你想要那个,你可以只删除内部循环中的 setOuterExit 调用 - 它也给出 3 作为输出。

现在,内部 setOuterExit 调用分配给 exit 的值正在被外部 setOuterExit 调用“覆盖”,因此外部循环不会立即中断它击中了内部 setOuterExit。我们可以将 exit 的赋值更改为:

action((b) => exit |= b); 

因此,如果 exit 被设置为 true,则没有其他值可以覆盖它。这将解决这个问题,但请注意 setOuterExit 仍然不会像真正的 break; 语句那样工作。 setOuterExit 之后的代码仍然会被执行,例如