Home

C++/CLI Collections: .NET Support Enumerating the Members of a Collection

 

Introduction to the IEnumerator Interface

The IEnumerator interface provides the means of identifying the class that holds a sample of the items that will be enumerated. This interface is equipped with one property and two methods. To use the functionalities provided by the IEnumerator interface, you must create a class that implements it. You can start the class as follows:

using namespace System;
using namespace System::Collections;

public ref class CEnumerator : public IEnumerator
{
};

If your collection is an array-based list, you can start by declaring the base array in the class: Here is an example:

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

If the collection is not array-based, you can declare a variable for the class that would be enumerated.

The role of the enumerator is to act on a collection. For this reason, the class should be prepared to receive an external collection. This can be done by passing it to a constructor of the enumerator. Here is an example:

using namespace System;
using namespace System::Collections;

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

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

CEnumerator::CEnumerator(array<double> ^ list)
{
}

The internal collection would be used in the enumerator class. The external collection would be the source of the values of the list that would be enumerated. For these reasons, you can/should initialize the internal collection with the values of the external list. This can be done as follows:

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

Practical Learning Practical Learning: Introducing Enumerations

  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 CCarIdentifier and click Finish
  4. Change the file as follows:
     
    #pragma once
    
    #include "CarInventory.h"
    
    using namespace System::Collections;
    
    public ref class CCarIdentifier : public IEnumerator
    {
    public:
        CCarInventory ^ counts;
        void Identify(CCarInventory ^ list);
    
        CCarIdentifier(void);
    };
  5. Access the CarIdentifier.cpp source file and change it as follows:
     
    #include "CarIdentifier.h"
    
    CCarIdentifier::CCarIdentifier(void)
    {
    }
    
    void CCarIdentifier::Identify(CCarInventory ^ list)
    {
        counts = list;
    }
  6. Save all

The Current Item of an Enumeration

When introducing some techniques of creating a list, we saw that you should have a type of tag, as a member variable, that allows you to monitor the item that is being currently accessed or used in the list. This is particularly valuable when visiting the members of the collection. The IEnumerator interface provides a property that is used to identify the current member of the list. This property is called Current. Because the current item is meant to be viewed only, the Current property is a read-only one. Based on the rules of abstract classes, remember that you must implement all members of an interface in the class that is based on it.

To implement the Current property, you can implement its get accessor to return the item at the current position. This can be done as follows:

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() { return numbers[cur]; }
    }
};

Practical Learning Practical Learning: Getting to the Current Item

  1. Access the CarIdentifier.h header file and implement the IEnumerator::Current property as follows:
     
    #pragma once
    
    #include "CarInventory.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CCarIdentifier : public IEnumerator
    {
    private:
        int curPosition;
    
    public:
        CCarInventory ^ counts;
        void Identify(CCarInventory ^ list);
    
        property Object ^ Current
        {
            virtual Object ^ get()
            {
                try {
                    return counts->Get(this->curPosition);
                }
                catch(IndexOutOfRangeException ^)
                {
                    Console::WriteLine(L"The current item must be accessed "
                                       L"within the range of available items");
                    return nullptr;
                }
            }
        }
    
        CCarIdentifier(void);
    };
  2. Access the CarIdentifier.cpp source file and change the constructor as follows:
     
    CCarIdentifier::CCarIdentifier(void)
    {
        curPosition = -1;
    }
  3. Save the file

Resetting the Tag of the Current Item

Although you should be able to identify the current item at any time, when the application starts, before the collection can be enumerated, the tag that is used to monitor the current item should be set to a value before the beginning of the count. This can be done by setting the tag to -1. Here is an example:

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

While the collection is being used, at one moment you may want to reset the tag of the current item to its original position. To support this operation, the IEnumerator interface is equipped with a method named Reset. Its syntax is:

void Reset();

When implementing this method, simply assign a non-existing value, which is usually -1, to the monitoring tag of the current item. This can be done as follows:

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() { return numbers[cur]; }
    }

    virtual void Reset();
};

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

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

When using the implementer of the IEnumerator interface, if you try accessing an item beyond the maximum number of items, the compiler would throw an IndexOutOfRangeException exception. For this reason, when anticipating a bad behavior, you should catch this exception when implementing the Current property. Here is an example:

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

Practical Learning Practical Learning: Resetting the Tag of the Current Item

  1. Access the CarIdentifier.h header file and declare the IEnumerator::Reset() method as follows:
     
    . . . No Change
    
    public ref class CCarIdentifier : public IEnumerator
    {
    private:
        int curPosition;
    
    public:
        
        . . . No Change
    
        virtual void Reset();
        CCarIdentifier(void);
    };
  2. Open the CarInventory.cpp source file and implement the Reset() method as follows:
     
    #include "CarIdentifier.h"
    
    . . . No Change
    
    void CCarIdentifier::Reset()
    {
        curPosition = -1;
    }
  3. Save all

Moving to the Next Item in the Enumerator

In the previous lesson, we saw that, when using the items of a collection, one way you can locate one item from another is to be able to jump from one item to the next. This operation is also very important when enumerating a collection. To support this operation, the IEnumerator interface is quipped with the MoveNext() method. Its syntax is:

bool MoveNext();

When implementing this method, first increment the tag that monitors the current item of the collection. After incrementing the tag, check whether it is lower than the total number of items. If it is, return true. Otherwise, return false. This can be done as follows:

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

    virtual void Reset();
    virtual bool MoveNext();
};

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

Practical Learning Practical Learning: Moving to the Next Item in the Enumerator

  1. Access the CarIdentifier.h header file and declare the IEnumerator::MoveNext() method as follows:
     
    #pragma once
    
    #include "CarInventory.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CCarIdentifier : public IEnumerator
    {
    private:
        int curPosition;
    
    public:
        CCarInventory ^ counts;
        void Identify(CCarInventory ^ list);
    
        property Object ^ Current
        {
            virtual Object ^ get()
            {
                try {
                    return counts->Get(this->curPosition);
                }
                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();
    
        CCarIdentifier(void);
    };
  2. Open the CarInventory.cpp source file and implement the Reset() method as follows:
     
    #include "CarIdentifier.h"
    
    CCarIdentifier::CCarIdentifier(void)
    {
        curPosition = -1;
    }
    
    void CCarIdentifier::Identify(CCarInventory ^ list)
    {
        counts = list;
    }
    
    void CCarIdentifier::Reset()
    {
        curPosition = -1;
    }
    
    bool CCarIdentifier::MoveNext()
    {
        curPosition++;
    
        if( curPosition < counts->Count )
            return true;
        else
            return false;
    }
  3. Save all
 

Previous Copyright © 2007-2013, FunctionX Next