在 Visual C++ 中实现 IEnumerator 时遇到问题

Trouble implementing IEnumerator in Visual C++

前段时间,我。然后我选择了另一种解决方案,所以我没有再访问它。现在,我需要它。但是,IEnumerable 现在需要一个 IEnumerator

我从头文件中的空声明开始:

public ref class MyEnumerator : IEnumerator<MyClass^> {
};

当我尝试编译它时,编译器抱怨(它应该):

Error   1   error C3766: 'Foo::MyEnumerator' must provide an implementation for the interface method 'System::Object ^System::Collections::IEnumerator::Current::get(void)'

据我从其他 post 了解到,这是一种 .net 1.x 兼容方法。

所以,当我按照我的想法去做时,我必须:

public ref class MyEnumerator : IEnumerator<MyClass^> {
public:
    virtual System::Object Get1() = System::Collections::IEnumerator::Current::get {
        return nullptr;
    }
};

我现在得到:

Error   2   error C3671: 'Foo::Enumerator::Get1' : function does not override 'System::Collections::IEnumerator::Current::get'

我确实搜索过这个,但是搜索关键字 "visual c++" "IEnumerator" 和 "visual c++" "implement" "IEnumerator" 没有产生可用的搜索结果.不幸的是,我无法在 VB.net 或 C# 中实现这部分,这会使这更容易,因为这是连接甚至 COM 不可见的非托管第三方 DLL 的可怕部分。

那么,我该如何做对呢?或者我在哪里可以找到 IEnumerator?

的示例实现

请记住,非常很少需要实现您自己的迭代器。您几乎总是只依赖于 .NET Framework 实现的现有工具。但是当您实现自己的集合 class 时,您将需要一个。很遗憾你没有展示你的,我得补一个。

假设您有一个存储 MyClass 对象并实现 IEnumerable<> 的 MyClassCollection。要用作可索引的集合,它需要一个 Count 属性 来指示元素的数量和一个索引器 return 来自集合的 MyClass 元素:

using namespace System;
using namespace System::Collections::Generic;

public ref class MyClass {};

public ref class MyClassCollection : IEnumerable<MyClass^> {
internal:
    int version;
public:
    property int Count {                // Needs implementation
        int get();
    }
    property MyClass^ default[int] {    // Needs implementation
        MyClass^ get(int index);
    }
    virtual IEnumerator<MyClass^>^ GetEnumerator();
internal:
    virtual System::Collections::IEnumerator^ GetEnumerator1() = System::Collections::IEnumerable::GetEnumerator{
        return GetEnumerator();
    }
};

我没有包括像 Add() 和 Remove() 这样的成员。每当集合发生变化时增加 version 成员,这在枚举器中很有用,可以检测客户端代码是否继续迭代集合,即使它已发生变化。


您的 MyEnumerator class 需要实现 IEnumerator<> 中的 4 个接口成员和一个实现 IDisposable 的析构函数。使用传递集合对象的内部构造函数:

public ref class MyEnumerator : IEnumerator<MyClass^> {
private:
    MyClassCollection^ collection;
    int index;
    int version;
internal:
    MyEnumerator(MyClassCollection^ source) : collection(source), 
        index(0), version(source->version) {}
public:
    ~MyEnumerator() {}

    virtual bool MoveNext() {
        if (index >= collection->Count) return false;
        if (collection->version != version) collectionChanged();
        index++;
        return true;
    }

    virtual void Reset() {
        index = 0;
    }

    virtual property MyClass ^ Current {
        MyClass^ get() = IEnumerator<MyClass^>::Current::get {
            if (collection->version != version) collectionChanged();
            return collection[index];
        }
    }
internal:
    virtual property System::Object ^ Current1 {
        Object^ get() = System::Collections::IEnumerator::Current::get{
            return Current;
        }
    }
private:
    void collectionChanged() {
        throw gcnew InvalidOperationException("Collection has changed");
    }
};

除了通常笨拙的显式接口实现语法外,这里没什么可看的。析构函数很少需要做任何重要的事情,所以 {} 是完全正常的。请注意 version 检查如何检测客户端代码继续迭代已更改的集合。 collectionChanged() 方法是有意分开的,这允许内联 MoveNext 和 Current 成员。我假设 MyClassCollection 索引器已经实现了边界检查,所以没有在 Current 属性 getter 中检查它。

现在您可以编写 GetEnumerator() 方法:

IEnumerator<MyClass^>^ MyClassCollection::GetEnumerator() {
    return gcnew MyEnumerator(this);
}