【问题标题】:Simple IEnumerator use (with example)简单的 IEnumerator 使用(示例)
【发布时间】:2011-09-05 16:10:02
【问题描述】:

我无法记住如何(但不知道为什么)在 C# 中使用 IEnumerators。我已经习惯了 Java 的精彩文档,它很好地向初学者解释了一切。所以,请多多包涵。

我尝试从这些板上的其他答案中学习,但无济于事。与其问一个以前已经问过的一般性问题,我有一个具体的例子可以为我澄清事情。

假设我有一个方法需要传递一个IEnumerable<String> 对象。该方法所需要做的就是将字母roxxors 连接到迭代器中每个String 的末尾。然后它将返回这个新的迭代器(当然原来的 IEnumerable 对象会保持原样)。

我该怎么办?当然,除了我之外,这里的答案应该可以帮助许多人解决有关这些对象的基本问题。

【问题讨论】:

    标签: c# ienumerator


    【解决方案1】:

    这是IEnumerator 上的文档。它们用于获取列表的值,其中长度不一定提前知道(即使它可能是)。这个词来自enumerate,意思是“数数或一一命名”。

    IEnumeratorIEnumerator<T> 由 .NET 中的所有 IEnumerableIEnumerable<T> 接口(后者提供两者)通过 GetEnumerator() 提供。这一点很重要,因为foreach 语句旨在通过这些接口方法直接与枚举器一起工作。

    例如:

    IEnumerator enumerator = enumerable.GetEnumerator();
    
    while (enumerator.MoveNext())
    {
        object item = enumerator.Current;
        // Perform logic on the item
    }
    

    变成:

    foreach(object item in enumerable)
    {
        // Perform logic on the item
    }
    

    对于您的具体场景,.NET 中的几乎所有集合都实现了IEnumerable。因此,您可以执行以下操作:

    public IEnumerator Enumerate(IEnumerable enumerable)
    {
        // List implements IEnumerable, but could be any collection.
        List<string> list = new List<string>(); 
    
        foreach(string value in enumerable)
        {
            list.Add(value + "roxxors");
        }
        return list.GetEnumerator();
    }
    

    【讨论】:

    • Reset() 不被 foreach 调用。它适用于 COM 互操作,并非所有枚举器都支持它(事实上大多数枚举器支持它)。
    • 枚举器是只读的,对吗?如何使用这种模式返回包含我的修改的枚举器类型?
    • @BlackVegetable IEnumerator 是只读的,但是,IEnumerable 通常可以转换回它的可变类型(例如((List&lt;string&gt;)foo.ReadOnlyValues).Add("Hahaha! So much for read only sucker!")) - 所以在假设IEnumerable 保护你免受这个。
    • @JonathanDickinson 呃...实际上,这会撤消all the benefits of using IEnumerable。典型的模式是返回一个带有新值的新 IEnumerable。这允许客户端代码决定何时评估可枚举的每个元素,而不是强制它们一次全部发生。
    • 别忘了Dispose() IEnumerator!
    【解决方案2】:
    public IEnumerable<string> Appender(IEnumerable<string> strings)
    {
      List<string> myList = new List<string>();
      foreach(string str in strings)
      {
          myList.Add(str + "roxxors");
      }
      return myList;
    }
    

    public IEnumerable<string> Appender(IEnumerable<string> strings)
    {
      foreach(string str in strings)
      {
          yield return str + "roxxors";
      }
    }
    

    使用yield construct,或者干脆

    var newCollection = strings.Select(str => str + "roxxors"); //(*)
    

    var newCollection = from str in strings select str + "roxxors"; //(**)
    

    其中两个使用LINQ(**) 只是(*) 的语法糖。

    【讨论】:

    • LINQ 的有趣模式。我得研究一下。谢谢大家的(快速)帮助!
    • 我似乎记得你应该尽量不要在声明为 IEnumerable 的方法中返回 List。原因是人们可能会“作弊”并注意到它实际上是一个列表并开始用它做列表的事情。 List(实际上是所有 IEnumerables)确实有一个 AsEnumerable() 方法,我认为应该调用并返回它。否则,产量和特别是 linq 响应的最佳答案。 :)
    • 如果您打算在 C# 中进行大量开发,您肯定会想在 LINQ 上投入一些时间 - 它会为您节省大量时间并让您对代码感觉更好 :-)
    • @chris:调用 .AsEnumerable() 并没有多大作用:stackoverflow.com/questions/17968469/… :-)
    • @rune:这有点像过去的爆炸。 :) 你是对的,IEnumerables 上的 AsEnumerable 方法没有任何用处。我的推理仍然是合理的(ish),但需要一种不同的方法来停止以列表的形式回退(例如.Selectg(x=&gt;x))。
    【解决方案3】:

    如果我对你的理解正确,那么在 c# 中,yield return 编译器魔法就是你所需要的。

    例如

    IEnumerable<string> myMethod(IEnumerable<string> sequence)
    {
        foreach(string item in sequence)
        {
             yield return item + "roxxors";
        }
    }
    

    【讨论】:

    • 那么在这种情况下,yield 在每次运行时都会从列表中返回一个(修改后的)字符串?还是会返回某种 IEnumerable 对象?
    • @BlackVegetable 是的,它会返回一个IEnumerable 对象,每次调用MoveNext 时都会构建一个字符串(直接或间接使用foreach)
    • 是的,它是语法糖,它告诉编译器把它变成一个迭代器块。见这里msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
    • 这是正确的方法,应该上去。接受的答案必须在返回之前构建整个列表,而不是遵循 IEnumerable 设计。
    【解决方案4】:

    我会这样做:

    private IEnumerable<string> DoWork(IEnumerable<string> data)
    {
        List<string> newData = new List<string>();
        foreach(string item in data)
        {
            newData.Add(item + "roxxors");
        }
        return newData;
    }
    

    简单的东西:)

    【讨论】:

    • 这是我的第一个想法。但是,我与之交互的其他方法要求我返回 IEnumerable 类型或类似的类型。不过感谢您的回复!
    • @BlackVegetable: List&lt;T&gt; 是一个IEnumerable&lt;T&gt;。但是,是的,有更好的方法来做到这一点(使用yield)。
    • 我似乎记得你应该尽量不要在声明为 IEnumerable 的方法中返回 List。原因是人们可能会“作弊”并注意到它实际上是一个列表并开始用它做列表的事情。 List(实际上是所有 IEnumerables)确实有一个 AsEnumerable() 方法,我认为应该调用并返回它。
    【解决方案5】:

    你也可以使用 LINQ 的 Select 方法:

    var source = new[] { "Line 1", "Line 2" };
    
    var result = source.Select(s => s + " roxxors");
    

    在此处阅读更多信息Enumerable.Select Method

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-28
      • 2019-08-02
      • 2016-03-02
      • 2012-06-09
      • 2013-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多