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);
}
}
};
}