反转一个可枚举的lambda函数

本文关键字:枚举 lambda 函数 一个 | 更新日期: 2023-09-27 18:08:42

我已经使用这个函数创建了一个lambda函数的ienumerable

    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函数。我该如何修改它以使其工作或着手编写一个工作的替代反向函数呢?

反转一个可枚举的lambda函数

问题是您正在捕获循环变量。所有的委托都在捕获相同的变量,所以它们总是会看到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的博客文章"关闭被认为有害的循环变量"以获取更多信息。请注意,foreach的行为可能会在c# 4.5中发生变化。

所有的lambda表达式都共享同一个a变量。
因为你只在循环结束后才调用它们,所以a总是3

你需要给每一个单独的变量:

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

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