在 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);
}
前段时间,我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);
}