Внедрение IEnumerable <T> в С++/CLI
У меня возникают проблемы с реализацией IEnumerable<T>
в моем классе пользовательской коллекции в С++/CLI. Вот соответствующая часть кода:
using namespace System::Collections::Generic;
ref class MyCollection : IEnumerable<MyClass^>
{
public:
MyCollection()
{
}
virtual IEnumerator<MyClass^>^ GetEnumerator()
{
return nullptr;
}
};
При компиляции это приводит к следующим ошибкам:
ошибка C2392: "System:: Подборки:: Общий:: IEnumerator ^ MyCollection:: GetEnumerator (аннулируются) ': Ковариантные типы возврата не поддерживается в управляемых типах, в противном случае" System:: Коллекция:: IEnumerator ^ Система:: Подборки:: IEnumerable:: GetEnumerator (аннулируются) "была бы переопределена ошибка C3766:" MyCollection "должен предоставить реализация для интерфейса метод" System:: Коллекция:: IEnumerator ^ Система:: Подборки:: IEnumerable:: GetEnumerator (аннулируются)
Это имеет смысл, так как IEnumerable<T>
происходит от IEnumerable
. Однако я не уверен, как исправить эту ошибку компиляции. Если бы это был С#, я бы неявно реализовал IEnumerable
, но я не уверен, как это сделать в С++/CLI (если это возможно):
class MyCollection : IEnumerable<MyClass>
{
public MyCollection()
{
}
public IEnumerator<MyClass> GetEnumerator()
{
return null;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Если я добавляю реализацию IEnumerable::GetEnumerator()
, компилятор жалуется на два метода, которые отличаются только типом возврата (что также имеет смысл).
Итак, как мне реализовать IEnumerable<T>
в классе С++/CLI?
Ответы
Ответ 1
Вы должны предоставить явную реализацию не общего метода GetEnumerator() и включить не общее пространство имен:
using namespace System::Collections;
....
virtual IEnumerator^ EnumerableGetEnumerator() = IEnumerable::GetEnumerator
{
return GetEnumerator<MyClass^>();
}
Обновление: Как упоминалось в комментариях, явная версия GetEnumerator должна быть названа разной, чтобы избежать столкновения имен, поэтому я назвал ее EnumerableGetEnumerator.
Аналогично, в С# вам нужно сделать это следующим образом:
using System.Collections.Generic;
public class MyCollection : IEnumerable<MyClass>
{
public MyCollection()
{
}
public IEnumerator<MyClass> GetEnumerator()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator<MyClass>();
}
}
Ответ 2
Это не очень просто. Вот мой удар. Заполнить бланки". Одна из самых больших проблем - двусмысленность, если вы используете как коллекцию, так и коллекцию:: Generic namespace. С++/CLI действительно боль.
using namespace System;
using namespace System::Collections;
public ref struct Enumerable : public Generic::IEnumerable<String^> {
public:
virtual Generic::IEnumerator<String^>^ GetEnumerator() sealed = Generic::IEnumerable<String^>::GetEnumerator {
return gcnew Enumerator();
}
virtual IEnumerator^ GetEnumeratorBase() sealed = IEnumerable::GetEnumerator {
return GetEnumerator();
}
private:
ref struct TagEnumerator : public Generic::IEnumerator<String^> {
public:
property String^ Current {
virtual String^ get() {
throw gcnew NotImplementedException();
}
};
property Object^ CurrentBase {
virtual Object^ get() sealed = IEnumerator::Current::get {
throw gcnew NotImplementedException();
}
};
virtual bool MoveNext() {
throw gcnew NotImplementedException();
}
virtual void Reset() {
throw gcnew NotImplementedException();
}
virtual ~Enumerator() {
}
};
};