反转可枚举的 lambda 函数

发布于 2024-12-05 03:21:37 字数 665 浏览 0 评论 0原文

我使用此函数创建了可枚举的 lambda 函数,

    static IEnumerable<Func<int>> MakeEnumerator(int[] values)
    {
        for (int a = 0; a < values.Length; a++)
        {
            yield return () => Values[a];
        }
    }

然后我无法使用 LINQ 反转它或转换为数组,除非所有值都成为最后一个函数。 示例代码(请注意,这只是演示了问题,而不是应用程序中的代码):

        int[] start = {1,2,3};

        IEnumerable<Func<int>> end = MakeEnumerator(start).Reverse<Func<int>>();

        foreach (Func<int> i in end)
        {
            Console.WriteLine(i());
        }

我认为问题出在 MakeEnumerator 函数中。我将如何修改它以使其工作或编写一个工作的替换反向函数。

I have created an ienumerable of lambda functions using this function

    static IEnumerable<Func<int>> MakeEnumerator(int[] values)
    {
        for (int a = 0; a < values.Length; a++)
        {
            yield return () => Values[a];
        }
    }

I cannot then reverse this using LINQ or convert into an array without all the values becoming the last function.
Example code (note this just demonstrates the problem it is not the code in the application):

        int[] start = {1,2,3};

        IEnumerable<Func<int>> end = MakeEnumerator(start).Reverse<Func<int>>();

        foreach (Func<int> i in end)
        {
            Console.WriteLine(i());
        }

I think the problem is in the MakeEnumerator function. How would I modify this to make it work or go about writing a working replacement reverse function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦屿孤独相伴 2024-12-12 03:21:37

问题是您正在捕获循环变量。您的所有委托都捕获相同的变量,因此他们始终会看到 a 的最新值...当您这样做时,该值将是 values.Length + 1在您的用例中执行委托。您可以简单地复制它:

for (int a = 0; a < values.Length; a++)
{
    int copy = a;
    yield return () => Values[copy];
}

或者(最好是 IMO)使用 foreach 循环,当前 需要相同的解决方法:

foreach (int value in values)
{
    int copy = value;
    yield return () => copy;
}

或者更好:

return values.Select(x => (Func<int>)(() => x));

或者:

Func<int, Func<int>> projection = x => () => x;
return values.Select(projection);

请参阅 Eric Lippert 的博客文章“关闭被认为有害的循环变量” 了解更多信息。请注意,对于 C# 4.5,foreach 的行为很可能会发生变化。

The problem is that you're capturing the loop variable. All of your delegates are capturing the same variable, so they'll always see the latest value of a... which will be values.Length + 1 by the time you're executing the delegates, in your use cases. You can simply copy it instead:

for (int a = 0; a < values.Length; a++)
{
    int copy = a;
    yield return () => Values[copy];
}

Alternatively (and preferrably IMO) use a foreach loop, which currently requires the same workaround:

foreach (int value in values)
{
    int copy = value;
    yield return () => copy;
}

Or better yet:

return values.Select(x => (Func<int>)(() => x));

Or:

Func<int, Func<int>> projection = x => () => x;
return values.Select(projection);

See Eric Lippert's blog post "Closing over the loop variable considered harmful" for more information. Note that the behaviour of foreach may well be changing for C# 4.5.

停顿的约定 2024-12-12 03:21:37

您的所有 lambda 表达式都是 共享同一个a变量
由于您仅在循环结束后调用它们,因此 a 始终为 3

您需要为每个变量提供自己的变量:

for (int dontUse = 0; dontUse < values.Length; dontUse++)
{
    int a = dontUse;
    yield return () => Values[a];
}

在此代码中,每个 lambda 表达式都有自己的 a 变量(因为它的作用域位于循环内部),并且这些单独的变量永远不会改变。

All of your lambda expressions are sharing the same a variable.
Since you're only calling them after the loop finishes, a is always 3.

You need to give each one its own variable:

for (int dontUse = 0; dontUse < values.Length; dontUse++)
{
    int a = dontUse;
    yield return () => Values[a];
}

In this code, each lambda expression gets its own a variable (since it's scoped inside the loop), and these separate variables never change.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文