Home

C++/CLI .NET Support for Collections: An Enumerable Collection

 

Introduction

The IEnumerator interface is used to set up a collection for enumeration. To use for each, you cannot use the IEnumerator interface. Therefore, the next step is to implement another interface called IEnumerable. While the IEnumerator interface is used to identify the class that holds each value that will be visited, the IEnumerable interface is used to communicate with the collection whose items will be enumerated. For this reason, when implementing this interface, you should provide the means of accessing the external collection. This can be done by passing a collection of the class that holds the values, to a constructor of the IEnumerable implementer.

 

Getting the Enumerator

To implement the IEnumerable interface, start by deriving a class from it. While the class implemented by the IEnumerator interface represents an object, the class that implements the IEnumerable interface is a collection. Here is an example:

using namespace System::Collections;

public ref class CEnumerable : public IEnumerable
{
};

The new class doesn't know what collection it will be asked to enumerate. For this reason, in the new class, you should declare a member variable of the class that holds the values that will be enumerated. If the collection is array-based, you can create the member variable as follows:

public ref class CEnumerable : public IEnumerable
{
private:
    array<double> ^ numbers;
};

Eventually, when instantiating the IEnumerable implementer, you will need to pass it a collection of values. To make this possible, you can create a method in the new class and pass that collection of objects. Here is an example:

using namespace System::Collections;

public ref class CEnumerable : public IEnumerable
{
private:
    array<double> ^ numbers;

public:
    void Identify(array<double> ^ values);
};

In this method, you can assign the member variable to the argument. You should also assign each member of the argument to its equivalent of the member of the argument. This can be done as follows:

void CEnumerable::Identify(array<double> ^ values)
{
    numbers = values;
    for(int i = 0; i < values->Length; i++)
        numbers[i] = values[i];
}

To support the use of the for each loop, the IEnumerable interface is equipped with (only) a (one) method named GetEnumerator that you must implement. The IEnumerable::GetEnumerator() method returns an IEnumerator object:

public ref class CEnumerable : public IEnumerable
{
private:
    array<double> ^ numbers;

    void Identify(array<double> ^ values);
    virtual IEnumerator ^ GetEnumerator();
};

When implementing this method, you can return an object of the class that implements the IEnumerator interface, passing it the collection that was declared in the IEnumerable implementer. This can be done as follows: 

#include "Enumerable.h"
#include "Enumerator.h"

void CEnumerable::Identify(array<double> ^ values)
{
    numbers = values;
    for(int i = 0; i < values->Length; i++)
        numbers[i] = values[i];
}

IEnumerator ^ CEnumerable::GetEnumerator()
{
    return gcnew CEnumerator(numbers);
}

Practical Learning Practical Learning: Getting the Enumerator

  1. To create a new class, in the Class View, right-click BethesdaCarRental1 -> Add -> Class...
  2. In the Templates list, click C++ Class and click Add
  3. Set the Name of the class to CCars and click Finish
  4. Change the Cars.h header file as follows:
     
    #pragma once
    
    #include "CarInventory.h"
    #include "CarIdentifier.h"
    
    using namespace System::Collections;
    
    public ref class CCars : public IEnumerable
    {
    private:
        CCarInventory ^ items;
    
    public:
        void Locate(CCarInventory ^ list);
        virtual IEnumerator ^ GetEnumerator(); 
    
        CCars(void);
    };
  5. Open the Cars.cpp source file and change it as follows:
     
    #include "Cars.h"
    
    CCars::CCars(void)
    {
    }
    
    void CCars::Locate(CCarInventory ^ list)
    {
        items = gcnew CCarInventory();
    
        for(int i = 0; i < list->Count; i++)
            items->Add(list->Get(i));
    }
    
    IEnumerator ^ CCars::GetEnumerator()
    {
        CCarIdentifier ^ cid = gcnew CCarIdentifier;
    
        cid->Identify(items);
        return cid; 
    }
  6. Save all

Using for each

After implementing the IEnumerator and the IEnumerable interfaces, you can then use the for each loop. To start, you must prepare the collection and its items for processing. Here is an example:

using namespace System;

int main()
{
    array<double> ^  numbers = gcnew array<double>(5);
    numbers[0] = 224.52;
    numbers[1] = 60.48;
    numbers[2] = 1250.64;
    numbers[3] = 8.86;
    numbers[4] = 1005.36;

    return 0;
}

To enumerate the collection, declare a variable based on the implementer of the IEnumerable and pass the collection to its constructor. Once this is done, you can then use the for each. Here is an example:

Header File: Enumerator.h
using namespace System;
using namespace System::Collections;

public ref class CEnumerator : public IEnumerator
{
private:
    array<double> ^ numbers;
    int cur;

public:
    CEnumerator(array<double> ^ list);

    virtual property Object ^ Current
    {
        Object ^ get()
        {
	    try {
                return numbers[cur];
	    }
            catch(IndexOutOfRangeException ^)
            {
		Console::WriteLine(L"The current item must be accessed "
                                   L"within the range of available items");
		return nullptr;
            }
        }
    }

    virtual void Reset();
    virtual bool MoveNext();
};
Source File: Enumerator.cpp
#include "Enumerator.h"

CEnumerator::CEnumerator(array<double> ^ list)
{
    numbers = list;
    cur = -1;
}

void CEnumerator::Reset()
{
    cur = -1;
}

bool CEnumerator::MoveNext()
{
    cur++;

    if( cur < numbers->Length )
        return true;
    else
        return false;
}
Header File: Enumerable.h
#pragma once
using namespace System::Collections;

public ref class CEnumerable : public IEnumerable
{
private:
    array<double> ^ numbers;

public:
    CEnumerable(void);

    void Identify(array<double> ^ values);
    virtual IEnumerator ^ GetEnumerator();
};
Source File: Enumerable.cpp
#include "Enumerable.h"
#include "Enumerator.h"

CEnumerable::CEnumerable(void)
{
}

void CEnumerable::Identify(array<double> ^ values)
{
    numbers = values;
    for(int i = 0; i < values->Length; i++)
        numbers[i] = values[i];
}

IEnumerator ^ CEnumerable::GetEnumerator()
{
    return gcnew CEnumerator(numbers);
}
Source File: Exercise.cpp
using namespace System;

#include "Enumerable.h"

int main()
{
    array<double> ^  numbers = gcnew array<double>(5);
    numbers[0] = 224.52;
    numbers[1] = 60.48;
    numbers[2] = 1250.64;
    numbers[3] = 8.86;
    numbers[4] = 1005.36;

    CEnumerable ^ coll = gcnew CEnumerable;
        
    coll->Identify(numbers);
    for each(double d in coll)
        Console::WriteLine(L"Item {0}", d);

    return 0;
}

    This would produce:

Item 224.52
Item 60.48
Item 1250.64
Item 8.86
Item 1005.36
Press any key to continue . . .

Practical Learning Practical Learning: Using for each on an Enumerator

  1. To create a new file, in the Solution Explorer, right-click BethesdaCarRental1 -> Add -> New Item...
  2. In the Templates list, click C++ File (.cpp)
  3. Set the Name to Exercise and click OK
  4. Implement the file as follows:
     
    #include "CarInventory.h"
    #include "Car.h"
    #include "Cars.h"
    
    using namespace System;
    
    int main()
    {
        CCarInventory ^ cars = gcnew CCarInventory;
        CCar ^ nice;
    
        nice = gcnew CCar;
        nice->TagNumber    = L"527 495";
        nice->Make         = L"Honda";
        nice->Model        = L"Civic";
        nice->CarYear      = 2006;
        nice->Mileage      = 8631;
        nice->Category     = L"Compact";
        nice->HasK7Player  = false;
        nice->HasCDPlayer  = true;
        nice->HasDVDPlayer = false;
        nice->Available    = true;
        cars->Add(nice);
    
        nice = gcnew CCar;
        nice->TagNumber    = L"M838400";
        nice->Make         = L"Ford";
        nice->Model        = L"Expedition";
        nice->CarYear      = 2004;
        nice->Mileage      = 48631;
        nice->Category     = L"SUV";
        nice->HasK7Player  = false;
        nice->HasCDPlayer  = true;
        nice->HasDVDPlayer = true;
        nice->Available    = false;
        cars->Add(nice);
    	
        nice = gcnew CCar;
        nice->TagNumber    = L"LRT825";
        nice->Make         = L"Kia";
        nice->Model        = L"Rio";
        nice->CarYear      = 2007;
        nice->Mileage      = 12504;
        nice->Category     = L"Economy";
        nice->HasK7Player  = false;
        nice->HasCDPlayer  = false;
        nice->HasDVDPlayer = false;
        nice->Available    = false;
        cars->Add(nice);
    	
        nice = gcnew CCar;
        nice->TagNumber    = L"917035";
        nice->Make         = L"Toyota";
        nice->Model        = L"Camry";
        nice->CarYear      = 2006;
        nice->Mileage      = 10664;
        nice->Category     = L"Full Size";
        nice->HasK7Player  = true;
        nice->HasCDPlayer  = true;
        nice->HasDVDPlayer = false;
        nice->Available    = true;
        cars->Add(nice);
    
        CCars ^ collection = gcnew CCars;
        collection->Locate(cars);
    
        Console::WriteLine(L"=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=");
        Console::WriteLine(L"Total: {0} Cars in company inventory",
                    cars->Count);
        Console::WriteLine(L"=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=");
        Console::WriteLine(L"Inventory Summary");
        for each(CCar ^ car in collection)
        {
            Console::WriteLine(L"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
            Console::WriteLine(L"Car Information");
            Console::WriteLine(L"-------------------------------");
    		Console::WriteLine(L"Tag #:      {0}", car->TagNumber);
            Console::WriteLine(L"Make:       {0}", car->Make);
            Console::WriteLine(L"Model:      {0}", car->Model);
            Console::WriteLine(L"Year:       {0}", car->CarYear);
            Console::WriteLine(L"Mileage:    {0}", car->Mileage);
            Console::WriteLine(L"Category:   {0}", car->Category);
            Console::WriteLine(L"K7 Plaher:  {0}", car->HasK7Player);
            Console::WriteLine(L"CD Player:  {0}", car->HasCDPlayer);
            Console::WriteLine(L"DVD Plaher: {0}", car->HasDVDPlayer);
            Console::WriteLine(L"Available:  {0}", car->Available);
        }
        Console::WriteLine(L"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
        return 0;
    }
  5. Execute the application to see the result:
     
    =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
    Total: 4 Cars in company inventory
    =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
    Inventory Summary
    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Car Information
    -------------------------------
    Tag #:      527 495
    Make:       Honda
    Model:      Civic
    Year:       2006
    Mileage:    8631
    Category:   Compact
    K7 Plaher:  False
    CD Player:  True
    DVD Plaher: False
    Available:  True
    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Car Information
    -------------------------------
    Tag #:      M838400
    Make:       Ford
    Model:      Expedition
    Year:       2004
    Mileage:    48631
    Category:   SUV
    K7 Plaher:  False
    CD Player:  True
    DVD Plaher: True
    Available:  False
    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Car Information
    -------------------------------
    Tag #:      LRT825
    Make:       Kia
    Model:      Rio
    Year:       2007
    Mileage:    12504
    Category:   Economy
    K7 Plaher:  False
    CD Player:  False
    DVD Plaher: False
    Available:  False
    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Car Information
    -------------------------------
    Tag #:      917035
    Make:       Toyota
    Model:      Camry
    Year:       2006
    Mileage:    10664
    Category:   Full Size
    K7 Plaher:  True
    CD Player:  True
    DVD Plaher: False
    Available:  True
    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Press any key to continue . . .
  6. Close the DOS window
 

Previous Copyright © 2007-2012 FunctionX Home