无法在Visual C ++中实现IEnumerator

时间:2015-08-03 09:13:08

标签: .net visual-c++ c++-cli

前一段时间,我asked about overriding IEnumerable in VC++。然后我接着另一个解决方案,所以我没有再访问它。现在,我需要它。但是,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)'

正如我在其他帖子中所理解的那样,这是一种.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#中实现这一部分,这将使这更容易,因为这是连接非托管第三方DLL的可怕部分,甚至连COM都不可见。

那么,我该如何做到这一点?或者我在哪里可以找到IEnumerator的示例实现?

1 个答案:

答案 0 :(得分:1)

请记住,实现自己的迭代器很少需要非常。您几乎总是依赖于.NET Framework实现的库存。但是当你实现自己的集合类时,你需要一个。不幸的是,你没有展示你的,我必须做一个。

假设您有一个存储MyClass对象的MyClassCollection并实现IEnumerable&lt;&gt;。要用作可索引集合,它需要一个Count属性来指示元素的数量,并需要一个索引器来从集合中返回一个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类需要实现IEnumerator中的4个接口成员&lt;&gt;和一个实现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);
}