c# - 在 foreach 循环中访问 Enumerator?

标签 c# foreach ienumerator

我有一个 List 类,我想覆盖 GetEnumerator() 以返回我自己的 Enumerator 类。此 Enumerator 类将具有两个附加属性,这些属性将在使用 Enumerator 时更新。

为简单起见(这不是确切的业务案例),假设这些属性是 CurrentIndexRunningTotal

我可以在 foreach 循环中手动管理这些属性,但我宁愿封装此功能以供重用,而 Enumerator 似乎是正确的位置。

问题: foreach 隐藏了所有枚举器业务,那么有没有办法在 foreach 语句中访问当前枚举器以便检索我的属性?还是我必须 foreach,使用讨厌的旧 while 循环,并自己操作枚举器?

最佳答案

严格来说,我会说,如果您想完全按照您所说的去做,那么是的,您需要调用 GetEnumerator 并使用 while 循环自己控制枚举器。

在不太了解您的业务需求的情况下,您也许可以利用迭代器函数,例如:

    public static IEnumerable<decimal> IgnoreSmallValues(List<decimal> list)
    {
        decimal runningTotal = 0M;
        foreach (decimal value in list)
        {
            // if the value is less than 1% of the running total, then ignore it
            if (runningTotal == 0M || value >= 0.01M * runningTotal)
            {
                runningTotal += value;
                yield return value;
            }
        }
    }

然后你可以这样做:

        List<decimal> payments = new List<decimal>() {
            123.45M,
            234.56M,
            .01M,
            345.67M,
            1.23M,
            456.78M
        };

        foreach (decimal largePayment in IgnoreSmallValues(payments))
        {
            // handle the large payments so that I can divert all the small payments to my own bank account.  Mwahaha!
        }

更新:

好的,下面是我称之为“钓鱼钩”解决方案的后续内容。现在,让我添加一个免责声明,我真的想不出这样做的好理由,但您的情况可能有所不同。

这个想法是您只需创建一个传递给迭代器函数的“钓鱼钩”对象(引用类型)。迭代器函数操纵您的钓鱼钩对象,并且由于您在外部代码中仍然有对它的引用,因此您可以了解正在发生的事情:

    public class FishingHook
    {
        public int Index { get; set; }
        public decimal RunningTotal { get; set; }
        public Func<decimal, bool> Criteria { get; set; }
    }

    public static IEnumerable<decimal> FishingHookIteration(IEnumerable<decimal> list, FishingHook hook)
    {
        hook.Index = 0;
        hook.RunningTotal = 0;
        foreach(decimal value in list)
        {
            // the hook object may define a Criteria delegate that
            // determines whether to skip the current value
            if (hook.Criteria == null || hook.Criteria(value))
            {
                hook.RunningTotal += value;
                yield return value;
                hook.Index++;
            }
        }
    }

你可以像这样使用它:

        List<decimal> payments = new List<decimal>() {
            123.45M,
            .01M,
            345.67M,
            234.56M,
            1.23M,
            456.78M
        };

        FishingHook hook = new FishingHook();

        decimal min = 0;
        hook.Criteria = x => x > min; // exclude any values that are less than/equal to the defined minimum
        foreach (decimal value in FishingHookIteration(payments, hook))
        {
            // update the minimum
            if (value > min) min = value;

            Console.WriteLine("Index: {0}, Value: {1}, Running Total: {2}", hook.Index, value, hook.RunningTotal);
        }
        // Resultint output is:
        //Index: 0, Value: 123.45, Running Total: 123.45
        //Index: 1, Value: 345.67, Running Total: 469.12
        //Index: 2, Value: 456.78, Running Total: 925.90
        // we've skipped the values .01, 234.56, and 1.23

本质上,FishingHook 对象使您可以对迭代器的执行方式进行一些控制。我从这个问题中得到的印象是,你需要一些方法来访问迭代器的内部工作,这样你就可以在迭代过程中操纵它的迭代方式,但如果不是这种情况,那么这个解决方案可能为你所需要的而矫枉过正。

关于c# - 在 foreach 循环中访问 Enumerator?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1828881/

相关文章:

c# - 如何从 MultiSelectList 返回 MvcHtmlString

c# - 你如何让Word表格中的文本垂直对齐?

java - 显示 <c :forEach> loop 中的值

c# - 如果我只能定义一个 GetEnumerator,为什么要实现 IEnumerable(T)?

c# - 我的 IEnumerator 正在工作但没有等待

c# - 无论我输入什么数字,我的文本框总是与 '0' 进行比较

c# - Azure BlobBatchClient.DeleteBlobsAsync 始终返回 404 blob not found

c# - 简单的传统 foreach 到 Linq ForEach

ruby - 使用 `each` 而不是 `for` -`each` 循环

c# - 将 CollectionBase 转换为 List 或可与 Linq 一起使用的数据类型