C# 在没有 foreach 循环的情况下使用 IEnumerable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2248985/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:46:07  来源:igfitidea点击:

Using IEnumerable without foreach loop

c#ienumerableyield-return

提问by Mark

I've gotta be missing something simple here.

我必须在这里遗漏一些简单的东西。

Take the following code:

取以下代码:

public IEnumerable<int> getInt(){
  for(int i = 0; i < 10; i++){
   yield return i;
  }
}

I can call this with:

我可以这样称呼它:

foreach (int j in obj.getInt()){
  //do something with j
}

How can I use the getInt method without the foreach loop:

如何在没有 foreach 循环的情况下使用 getInt 方法:

IEnumerable<int> iter = obj.getInt();
// do something with iter ??

Thanks.

谢谢。

EDITS

编辑

For those wondering why I'd want this. I'm iterating two things:

对于那些想知道为什么我想要这个的人。我正在迭代两件事:

IEnumerator<int> iter = obj.getInt().GetEnumerator();
foreach(object x in xs){
  if (x.someCondition) continue;
  iter.MoveNext();
  int n = iter.current();
  x.someProp = n;
  etc...
}

采纳答案by CMS

You can get a reference to the Enumerator, using the GetEnumeratormethod, then you can use the MoveNext()method to move on, and use the Currentproperty to access your elements:

您可以Enumerator使用该GetEnumerator方法获取对 的引用,然后您可以使用该MoveNext()方法继续前进,并使用该Current属性访问您的元素:

var enumerator = getInt().GetEnumerator();
while(enumerator.MoveNext())
{
    int n = enumerator.Current;
    Console.WriteLine(n);
}

回答by zildjohn01

How about this?

这个怎么样?

IEnumerator<int> iter = obj.getInt();
using(iter) {
    while(iter.MoveNext()) {
        DoSomethingWith(iter.Current)
    }
}

回答by Eric Lippert

My advice: don't mess around with the enumerators at all. Characterize your problem as a series of operations on sequences. Write code to express those operations. Let the sequence operators take care of managing the enumerators.

我的建议是:根本不要乱搞枚举器。将您的问题描述为对序列进行的一系列操作。编写代码来表达这些操作。让序列运算符负责管理枚举器。

So let's see if I've got this straight. You have two sequences. Let's say { 2, 3, 5, 7, 12 } and { "frog", "toad" }. The logical operation you want to perform is, say "go through the first sequence. Every time you find a number divisible by three, get the next item in the second sequence. Do something with the resulting (number, amphibian) pair."

所以让我们看看我是否明白这一点。你有两个序列。假设 { 2, 3, 5, 7, 12 } 和 { "frog", "toad" }。您要执行的逻辑操作是,说“遍历第一个序列。每次找到一个可被 3 整除的数字时,获取第二个序列中的下一项。对得到的(数字,两栖动物)对进行处理。”

Easily done. First, filter the first sequence:

轻松完成。首先,过滤第一个序列:

var filtered = firstSequence.Where(x=>x%3 == 0);

Next, zip the filtered sequence with the second sequence:

接下来,用第二个序列压缩过滤后的序列:

var zipped = filtered.Zip(
             secondSequence, 
             (y, z)=> new {Number = x, Amphibian = y});

And now you can iterate over the zipped sequence and do whatever you want with the pairs:

现在您可以遍历压缩序列并使用这些对执行您想要的任何操作:

foreach(var pair in zipped)
    Console.WriteLine("{0} : {1}", pair.Number, pair.Amphibian);

Easy peasy, no messing about with enumerators.

简单易行,不要乱搞枚举器。

回答by Doug

Although the accepted answers are correct, notice that IEnumerator.Current is undefined before the first call to MoveNext().

尽管接受的答案是正确的,但请注意 IEnumerator.Current 在第一次调用 MoveNext() 之前是未定义的。

If you are iterating over a secondary array, you'll want something like:

如果您要迭代辅助数组,您将需要以下内容:

IEnumerable<Foo> Foo() { ... }

int AssignValues(List<TakesFoo> data) {
  var count = 0;
  var foo = Foo().GetEnumerator();

  // Step into the first element of the array;
  // doing this does not discard a value from the IEnumerator
  if (foo.MoveNext()) { 
    foreach (var x in data) {
      x.SetFoo(foo.Current);
      count += 1;
      if (!foo.MoveNext()) { 
        break;
      }
   }

   // Return count of assigned values
   return count;
}

回答by sanjuro

using for loop:

使用 for 循环:

for (var enumerator = getInt().GetEnumerator(); enumerator.MoveNext(); )
{
    Console.WriteLine(enumerator.Current);
}

回答by Groo

It's important to mention that the duty of the foreachloop is to dispose the enumerator if the instance implements IDisposable. In other words, foreachshould be replaced with something like:

值得一提的foreach是,如果实例实现了,则循环的职责是处理枚举器IDisposable。换句话说,foreach应该替换为:

var enumerator = enumerable.GetEnumerator();

try
{
    while (enumerator.MoveNext())
    {
        var item = enumerator.Current;
        // do stuff
    }
}
finally
{
    var disposable = enumerator as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}