C#:在何处实现自定义IEnumerator<;T>;

C#:在何处实现自定义IEnumerator<;T>;,c#,ienumerable,ienumerator,C#,Ienumerable,Ienumerator,假设我有一个实现IEnumerable的类。它当前使用GetEnumerator()方法中的yield关键字。但是现在我需要做更多的事情,比如说我想自己清理一下。为此,除非我忽略了什么,否则我需要实现IEnumerator接口。但是你说我应该在哪里做 类本身是否应该实现它并GetEnumerator()返回this?还是将其隐藏在私有类中更好?或者它应该是一个完全不同的类?对此有哪些常见做法?我会选择一个IEnumerator类。这将需要存储状态(当前位置),该状态不是集合的一部分,而是枚举过程

假设我有一个实现
IEnumerable
的类。它当前使用
GetEnumerator()
方法中的
yield
关键字。但是现在我需要做更多的事情,比如说我想自己清理一下。为此,除非我忽略了什么,否则我需要实现
IEnumerator
接口。但是你说我应该在哪里做


类本身是否应该实现它并
GetEnumerator()
返回
this
?还是将其隐藏在私有类中更好?或者它应该是一个完全不同的类?对此有哪些常见做法?

我会选择一个IEnumerator类。这将需要存储状态(当前位置),该状态不是集合的一部分,而是枚举过程的一部分。

如果在处理枚举器时只需清理一些资源,例如在
foreach
循环结束时,则可以使用现有资源进行清理,只需在迭代器方法中添加一个try/finally块

像这样:

public IEnumerator<T> GetEnumerator()
{
    try
    {
        // your iterator code here
    }
    finally
    {
        // cleanup code here
    }
}
public IEnumerator GetEnumerator()
{
尝试
{
//这里是您的迭代器代码
}
最后
{
//清理代码在这里
}
}

这就是它的全部内容。

您可能根本不需要为此编写类。迭代器方法可以返回
IEnumerable
,因此,如果您的类只需要实现
IEnumerable
而不需要其他任何东西,只需为整个过程编写迭代器方法

如果没有,那么您必须通过使用迭代器方法来执行
GetEnumerator
,从而坚持使用实现
IEnumerable
的外部类,那么您不必在迭代后执行任何很难清理的操作


IEnumerator
源自
IDisposable
。迭代器方法通过执行
finally
块或最后一次
返回后的任何代码来实现
Dispose

您可能想阅读
yield return
-看起来您编写了一个方法,但实际上您正在生成一个具有状态的类。@Earwicker,是的,我知道。所以这就是我提出私人课堂建议的原因。因为我猜最终会有点类似。虽然我真的没有一点线索:pI认为你不能在try块中让步?@csharptest.net-如果它后面只有finally块,你可以。这是不允许的,太棒了。我甚至不知道这是可能的。经过测试,
收益返回可以存在于try块中。但是,它不能存在于
finally
块中。而且,正如@Earwicker所指出的,它不能存在于具有
catch
块的
try
块中。@Earwicker-Doh-1对我来说,我不知道(很明显)感谢你提供的信息:)我最近写了一系列文章,解释为什么我们对收益率的去向有这些限制。看看你是否感兴趣。上次收益率回报后的代码?那怎么办?特别是如果
收益率
处于无限循环中…我的措辞真的很糟糕!如果可以访问上一次
收益返回
后的代码,但最后一次调用
IEnumerator.MoveNext
,而不是
Dispose
,则执行该代码。如果yield返回在一个无限循环中,那么该循环之后的代码将不可访问,编译器将告诉您。如果不是,则在调用方枚举集合中的所有项之后执行该代码。因此,无论枚举是完成还是放弃,都要使用finally块来执行,如果希望仅在枚举未放弃时执行,则将代码放在方法的末尾。