Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing IEnumerable<T> in C++/CLI

Tags:

.net

c++-cli

I'm having problems implementing IEnumerable<T> in my custom collection class in C++/CLI. Here is the relevant part of the code:

using namespace System::Collections::Generic;

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

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

When compiled, this results in the following errors:

error C2392: 'System::Collections::Generic::IEnumerator ^MyCollection::GetEnumerator(void)': covariant returns types are not supported in managed types, otherwise 'System::Collections::IEnumerator ^System::Collections::IEnumerable::GetEnumerator(void)' would be overridden error C3766: 'MyCollection' must provide an implementation for the interface method 'System::Collections::IEnumerator ^System::Collections::IEnumerable::GetEnumerator(void)'

This makes sense, since IEnumerable<T> derives from IEnumerable. However, I'm not sure how to fix this compile error. If this was C#, I would implicitly implement IEnumerable, however I'm not sure how to do that in C++/CLI (if that's even possible) like this:

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

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

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

If I do add an implementation of IEnumerable::GetEnumerator(), the compiler complains about two methods that differ only by return type (which also makes sense).

So, how do I implement IEnumerable<T> in a C++/CLI class?

like image 939
Andy Avatar asked Jan 25 '10 16:01

Andy


2 Answers

You must provide an explicit implementation of the non-generic GetEnumerator() method and include the non-generic namespace:

using namespace System::Collections;

....

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

Update: As mentioned in the comments, the explicit version of GetEnumerator must be named different to avoid name clash, thus I've named it EnumerableGetEnumerator.

Similarly, in C# you would have to do it like this:

using System.Collections.Generic;

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

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

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator<MyClass>();
    }
}
like image 136
Peter Lillevold Avatar answered Sep 23 '22 05:09

Peter Lillevold


It is not very straightforward. Here is my stab at it. Fill in the "blanks". One of the biggest issues is the ambiguity if you use both Collections and Collections::Generic namespace. C++/CLI is really a pain.

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() {
        }
    };
};
like image 37
GotVino Avatar answered Sep 21 '22 05:09

GotVino