C# 编写自定义迭代器时,如何避免编译器生成引发异常的Reset()方法?

C# 编写自定义迭代器时,如何避免编译器生成引发异常的Reset()方法?,c#,exception,iterator,C#,Exception,Iterator,我编写了一个自定义迭代器作为解决复杂COM互操作问题的方法。迭代器非常简单: public IEnumerator GetEnumerator() { yield return DriveRates.driveSidereal; yield return DriveRates.driveKing; yield return DriveRates.driveLunar; yield return DriveRa

我编写了一个自定义迭代器作为解决复杂COM互操作问题的方法。迭代器非常简单:

    public IEnumerator GetEnumerator()
        {
        yield return DriveRates.driveSidereal;
        yield return DriveRates.driveKing;
        yield return DriveRates.driveLunar;
        yield return DriveRates.driveSolar;
        }
DriveRates
是一个枚举

我的理解是,编译器应该将其转换为状态机,确实如此,但当客户端应用程序使用该代码时,我会遇到以下异常:

System.NotSupportedException: Specified method is not supported. at TiGra.Astronomy.AWRDriveSystem.TrackingRates.d__0.System.Collections.IEnumerator.Reset() at System.Runtime.InteropServices.CustomMarshalers.EnumVariantViewOfEnumerator.Reset() at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) at System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.Reset() [...client app]
嗯,我想这就是例外的原因,但是。。。wwhhyyyyy?在这种情况下,重置简单地重置状态机并非不可能。有没有办法让编译器生成一个不抛出的Reset()方法?

没有,你不能。状态机可以重置的假设确实适用于您的简单情况,但是请注意,您可以编写具有副作用的迭代器,并且编译器不能假设状态机在一般情况下是纯的。因此,安全的做法是简单地禁止使用
Reset
功能(顺便说一句,该功能很少使用,我认为这与其说是一个有用的功能,不如说是一个设计错误)

代码最简单的解决方法是

public IEnumerator GetEnumerator()
{
    return new[] {
        DriveRates.driveSidereal,
        DriveRates.driveKing,
        DriveRates.driveLunar,
        DriveRates.driveSolar
    }.GetEnumerator();
}

我假设
DriveRates
中的值在枚举过程中不会发生变化,在这种情况下,代码不会产生相同的结果:这个版本很急切。

Ah。我有没有提到这是一个复杂的COM互操作问题?客户端应用程序阻塞了System.Array提供的迭代器,因此我为数组编写了一个自定义迭代器;-)事实上,发生的情况是,当客户端应用程序尝试对IEnumerable执行foreach()操作时,它没有正确封送处理,并收到一个NullReferenceException。不过,我会尝试这种方法,以防万一。谢谢你的建议,我很感激。我感觉你被困在这里了。试着发布另一个关于你的COM问题的问题,这可能会对你的案例更有用。卢卡斯,我明白你的意思,你没有错。然而,真正的问题可能还要花750万年的时间!但说真的,我会看看我是否能想出一个恰当的措辞。
public IEnumerator GetEnumerator()
{
    return new[] {
        DriveRates.driveSidereal,
        DriveRates.driveKing,
        DriveRates.driveLunar,
        DriveRates.driveSolar
    }.GetEnumerator();
}