Реализация IEnumerable <T> в C++ / CLI

У меня есть проблемы при реализации IEnumerable<T> в моем пользовательском классе набора в C++ / CLI. Вот соответствующая часть кода:

using namespace System::Collections::Generic;

ref class MyCollection : IEnumerable<MyClass^>
{
public:
    MyCollection()
    {
    }  

    virtual IEnumerator<MyClass^>^ GetEnumerator()
    {
        return nullptr;
    }
};

При компиляции это приводит к следующим ошибкам:

ошибка C2392: 'Система:: Наборы:: Универсальный:: IEnumerator ^MyCollection:: GetEnumerator (пусто)': ковариантные типы возвратов не поддерживаются в управляемых типах, иначе 'Система:: Наборы:: IEnumerator ^System:: Наборы:: IEnumerable:: GetEnumerator (пусто)' был бы переопределенной ошибкой C3766: 'MyCollection' должен обеспечить реализацию для метода интерфейса 'Система:: Наборы:: IEnumerator ^System:: Наборы:: IEnumerable:: GetEnumerator (пусто)'

Это имеет смысл с тех пор IEnumerable<T> происходит из IEnumerable. Однако я не уверен, как зафиксировать эту ошибку компиляции. Если бы это было C#, то я неявно реализовал бы IEnumerable, однако я не уверен, как сделать это в C++ / 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> в C++ / класс CLI?

14
задан Deduplicator 9 March 2015 в 19:55
поделиться

2 ответа

Вы должны предоставить явную реализацию нерегинного метода Getnumerator () и включают в себя небродное пространство имен:

using namespace System::Collections;

....

virtual IEnumerator^ EnumerableGetEnumerator() = IEnumerable::GetEnumerator
{
    return GetEnumerator<MyClass^>();
}

Обновление: Как упоминалось в комментариях, явная версия GetEnumerator должен быть назван другим, чтобы избежать столкновения, поэтому я назвал его enumerableTeTenUmerator.

Точно так же, в C # вам придется сделать это так:

using System.Collections.Generic;

public class MyCollection : IEnumerable<MyClass>
{
    public MyCollection()
    {
    }  

    public IEnumerator<MyClass> GetEnumerator()
    {
        return null;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator<MyClass>();
    }
}
18
ответ дан 1 December 2019 в 09:01
поделиться

Это не очень просто. Вот моя попытка. Заполните "пробелы". Одна из самых больших проблем - неоднозначность, если вы используете и Collections, и пространство имен Collections::Generic. C++/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() {
        }
    };
};
12
ответ дан 1 December 2019 в 09:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: