Implementing IEnumerable<T> in C++/CLI

by Brian Ensink 4. February 2010 22:02

Most of the .NET code I write is in C# but occasionally I need to write mixed mode C++/CLI code to expose some existing unmanaged code to our new .NET code.  C++/CLI works very well for this kind of interop but the language is much less familiar to me than C#. 

For example today I wanted to implement a property on a C++/CLI class that returned IEnumerable<T> to expose an unmanaged collection.  In C# this is a very easy with the yield keyword but there is no equivalent in C++/CLI so the enumerator classes have to implemented manually.  I got hung up on the syntax and it to took me far to many google searches before finally piecing it together.  So here is a complete but simple example implementation of IEnumerable<T> in C++/CLI.

You can download the full code here.

#pragma once
using namespace System;
namespace CppLibrary
{
public ref class Earth
{
private:
ref class EarthContinents : System::Collections::Generic::IEnumerable<String^>
{
private:
Earth^ _earth;

public:
EarthContinents(Earth^ Earth)
{
_earth = Earth;
}

virtual System::Collections::Generic::IEnumerator<String^>^ GetEnumerator_Generic() sealed
= System::Collections::Generic::IEnumerable<String^>::GetEnumerator
{
return gcnew EarthContinentsEnumerator(this);
}

virtual System::Collections::IEnumerator^ GetEnumerator_NonGeneric() sealed
= System::Collections::IEnumerable::GetEnumerator
{
return GetEnumerator_Generic();
}

private:
ref class EarthContinentsEnumerator : System::Collections::Generic::IEnumerator<String^>
{
private:
EarthContinents^ _continents;
int _index;

public:
EarthContinentsEnumerator(EarthContinents^ Continents)
{
_continents = Continents;
Reset();
}

~EarthContinentsEnumerator() { }

virtual bool MoveNext()
{
_index += 1;
return _index < _continents->_earth->_arr->Length;
}

property String^ Current_Generic
{
virtual String^ get() sealed
= System::Collections::Generic::IEnumerator<String^>::Current::get
{
return _continents->_earth->_arr[_index];
}
}

property Object^ Current_NonGeneric
{
virtual Object^ get() sealed
= System::Collections::IEnumerator::Current::get
{
return Current_Generic;
}
}

virtual void Reset()
{
_index = -1;
}
};
};

private:
array<String^>^ _arr;

public:
Earth()
{
_arr = gcnew array<String^>(7);
_arr[0] = gcnew String(L"Asia");
_arr[1] = gcnew String(L"Africa");
_arr[2] = gcnew String(L"North America");
_arr[3] = gcnew String(L"South America");
_arr[4] = gcnew String(L"Antarctica");
_arr[5] = gcnew String(L"Europe");
_arr[6] = gcnew String(L"Australia");
}

property System::Collections::Generic::IEnumerable<String^>^ Continents
{
System::Collections::Generic::IEnumerable<String^>^ get()
{
return gcnew EarthContinents(this);
}
}
};
}

Tags:

Software Development

Comments are closed

About the author

I am currently a .NET developer and really enjoy the platform.  .NET seems to be able to take the developer whereever he/she wants to go.  To the desktop, to the web, to a database, etc.  At my day job I write desktop apps but I also like to toy with other tech as I have time.