Built-In Collection Interfaces

 

Overview of .NET Collection Interfaces

 

Introduction

In the previous lesson, we saw how to create a collection class that can be enumerated. This was meant to lay a foundation for the wider set of collection classes available in the .NET Framework. In the next lesson, we will review some of the collection classes you can use in your project. Those classes were created by regular programmers like you to make it possible to directly use a collection without having to create one yourself. When you use some of those classes, they may not suit some particular need you have or they may not really be the type of collection appropriate for your application. In fact, after checking the .NET Framework built-in collection classes, you may not find the particular functionality you are looking for. As we saw in the previous two lessons, an alternative is to create your own collection class, which you can do from scratch.

To make it possible or even easier for anybody to create a good functional collection, you can use a class or derive one from those that ship with the .NET Framework. Collections are highly used by various other classes and Windows controls available in Microsoft Visual Studio. To provide a common functionality to the collections, sets, and series used in Windows applications and databases, the .NET Framework provides various interfaces that you can implement. Doing this gives you the double advantage of creating a collection class and getting familiar with the common collections you will use in graphical applications.

Choosing a Class or an Interface

When you want to use a collection in your application, you may first check what classes are available in the .NET Framework. If you don't find a suitable class, you can create your own that implements one or more interfaces. As it happens, the .NET Framework ships with many of them and your next step is to choose which one you prefer. Some of the most commonly used interfaces are

The ICollection Interface

 

Introduction

In our introduction to collections, we saw that one of the primary pieces of information you should always provide about a collection is the number of items it is (currently) holding. When creating a collection class, to prepare it to provide this valuable information, you can (should) implement an interface named ICollection. The ICollection interface is defined in the System::Collections namespace. This means that, if you are creating a class that implements it, you should include this namespace in the file. Here is an example:

using namespace System::Collections;

public ref class CCollection : public ICollection
{
};

Implementing ICollection

To assist you with keeping track of the number of items in a collection, the ICollection interface is equipped with a property named Count, which you must implement. To do this, you can create a private member variable that will actually keep a count of the number of items. The Count property can then be used to communicate this information to the clients of the class. Here is an example:

public ref class CCollection : public ICollection
{
private:
    int nbrOfStudents;

public:
    CCollection();

    virtual property int Count
    {
	int get() { return nbrOfStudents; }
    }
};

CCollection::CCollection()
{
    nbrOfStudents = 0;
}

The ICollection interface also allows its implementer to copy some of its items to an array. To provide this functionality, the interface is equipped with a method named CopyTo. The syntax of this method is:

void CopyTo(Array ^ array, int index);

This method takes two arguments. The first argument is the array that will receive the items. The second argument is the index of the item from where the copying operation will begin. Here is an example:

public ref class CCollection : public ICollection
{
private:
    int nbrOfItems;
    array<double> ^ numbers;

public:
    CCollection();

    virtual property int Count
    {
        int get() { return nbrOfItems; }
    }

    virtual void CopyTo(Array ^, int);
};

CCollection::CCollection()
{
    nbrOfItems = 0;
    numbers = gcnew array<double>(5);
}

void CCollection::CopyTo(Array ^ items, int index)
{
    array<double> ^ nbrs = gcnew array<double>(Count);

    for(int i = 0; i < Count; i++)
        nbrs[i] = numbers[i];
    items = nbrs;
}

If you create a collection class, you can provide the ability to enumerate its items. When this is done, some time to time, you will want to identify or to know what item is currently being accessed. In case other collection classes are using the same function at the time you are accessing this information, you should an object that is responsible for synchronizing the collection. To do this in your ICollection-based class, you must implement a property named SyncRoot. This property must return an Object handle. Here is an example:

public ref class CCollection : public ICollection
{
private:
    int nbrOfItems;

public:
    . . . No Change

    virtual property Object ^ SyncRoot
    {
        Object ^ get() { return this; }
    }
};

Besides the ability to specify the number of items in a collection, a class that implements the ICollection interface must retrieve a value that indicates whether its items is synchronized. To give this information, you must implements a Boolean property named IsSynchronized. Here is an example:

public ref class CCollection : public ICollection
{
private:
    int nbrOfItems;

public:
    . . . No Change

    virtual property bool IsSynchronized
    {
        bool get() { return false; }
    }
};

ICollection extends the IEnumerable interface. This means that you should be able to use for each in your ICollection-based class but you must create the functionality yourself, which is done by implementing the GetEnumerator() method. Even if you don't want to support this feature, you still must provide at least a skeleton for this method. Here is an example:

using namespace System;
using namespace System::Collections;

public ref class CCollection : public ICollection
{
private:
    int nbrOfItems;

public:
    . . . No Change

    virtual IEnumerator ^ GetEnumerator();
};

IEnumerator ^ CCollection::GetEnumerator()
{
    return nullptr;
}

The IList Interface

 

Introduction

While it provides the minimum functionality of a collection, the ICollection interface is not equipped to perform the regular operations of a collection class, such as adding, retrieving, or deleting items from a set. To assist you with creating a class as complete as possible, the .NET Framework provides an interface named IList. The IList interface, defined in the System::Collections namespace, is equipped with the methods necessary to add, insert, delete, or retrieve items from a collection. Because the functionalities of these methods may not suit you, to use these features, you must create a class that implements them.

Practical Learning Practical Learning: Starting a Custom Collection Class

  1. Start Microsoft Visual C++ and create a new CLR Empty Project named SolasPropertyRental1
  2. To create a new class, in the Solution Explorer, right-click Solas Property Rental1 -> Add -> Class...
  3. In the Templates list, click C++ Class and click Add
  4. Set the Name to CRentalProperty and press Enter
  5. Change the header file as follows:
    #pragma once
    
    using namespace System;
    
    public enum class PropertyTypes
    {
    	Apartment = 1,
    	Townhouse,
    	SingleFamily,
    	Unknown
    };
    
    public enum class PropertyConditions
    {
    	Excellent = 1,
    	Good,
    	BadShape,
    	Unknown
    };
    
    public ref class CRentalProperty
    {
    private:
        // These are the characteristics of a property
        long propCode;
        PropertyTypes type;
        PropertyConditions cond;
        short beds;
        double baths;
        double val;
    
    public:
        property long PropertyCode
        {
            long get() { return propCode; }
            void set(long value) { propCode = value; }
        }
    
        property PropertyTypes PropertyType
        {
            PropertyTypes get() { return type; }
            void set(PropertyTypes value) { type = value; }
        }
    
        property PropertyConditions PropertyCondition
        {
            PropertyConditions get() { return cond; }
            void set(PropertyConditions value) { cond = value; }
        }
    
        property short Bedrooms
        {
            short get() { return beds; }
            void set(short value) { beds = value; }
        }
    
        property double Bathrooms
        {
            double get() { return (baths <= 0) ? 0.00 : baths; }
            void set(double value) { baths = value; }
        }
    
        property double MonthlyRent
        {
            double get() { return (val <= 0) ? 0.00 : val; }
            void set(double value) { val = value; }
        }
    
    public:
        // This constructor is used to create 
        // default values for a property
    	CRentalProperty(void);
    };
  6. Open the RentalProperty.cpp source file and change it as follows:
    #include "RentalProperty.h"
    
    CRentalProperty::CRentalProperty(void)
    {
        propCode = 0;
        type     = PropertyTypes::Unknown;
        cond     = PropertyConditions::Unknown;
        beds     = 0;
        baths    = 0.0;
        val      = 0.00;
    }
  7. To create a new file, in the Solution Explorer, right-click Solas Property Rental1 -> Add -> New Item...
  8. In the Templates list, click C++ File (.cpp)
  9. Set the Name to Exercise and press Enter
  10. Change the file as follows:
    using namespace System;
    
    int main()
    {
        return 0;
    }
  11. Save all

Implementing IList

As mentioned above, to create a collection, you can derive it from the IList interface. Here is an example:

using namespace System::Collections;

public ref class CStudents : public IList
{
};

This IList interface is declared as follows:

public interface class IList : ICollection, IEnumerable

This means that the IList interface extends both the ICollection and the IEnumerable interfaces. This also implies that you must implement the members of these parent interfaces. In other words, you must implement the Count property, the SyncRoot property, the IsSynchronized property, and the CopyTo() method of the ICollection interface. From what we learned with ICollection, here are examples of implementing these members:

public ref class CObjects : public IList
{
private:
    int items;
    array<Object ^> ^ objects;

public:
    CObjects();

    virtual property int Count
    {
        int get() { return items; }
    }

    virtual property bool IsSynchronized
    {
	bool get() { return false; }
    }

    virtual property Object ^ SyncRoot
    {
	Object ^ get() { return this; }
    }

    virtual void CopyTo(Array ^, int);
};

CObjects::CObjects()
{
    items = 0;
    objects = gcnew array<Object ^>(5);
}

void CObjects::CopyTo(Array ^ ary, int index)
{
    
}

You must also implement the GetEnumerator() method of the IEnumerable interface. If you don't have time to completely implement it, you can simply return nullptr. Here is an example:

using namespace System;
using namespace System::Collections;

public ref class CObjects : public IList
{
    . . . No Change

public:
    . . . No Change

    virtual void CopyTo(Array ^, int);
    virtual IEnumerator ^ GetEnumerator(void);
};

CObjects::CObjects()
{
    items = 0;
    objects = gcnew array<Object ^>(5);
}

IEnumerator ^ CObjects::GetEnumerator(void)
{
    return nullptr;
}

Practical Learning Practical Learning: Implementing the IList Interface

  1. To create a new class, in the Class View, right-click Solas Property Rental1 -> Add -> Class...
  2. In the Templates list, click C++ Class and click Add
  3. Set the Name to CProperties and press Enter
  4. Change the Properties.h header file as follows:
      
    #pragma once
    
    #include "RentalProperty.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CProperties : public IList
    {
    private:
        array<Object ^> ^ RentalProperties;
        int counter;
    	
    public:
        CProperties(void);
    
        virtual property int Count
        {
            int get() { return counter; }
        }
    
        virtual property bool IsSynchronized
        {
            bool get() { return false; }
        }
    
        virtual property Object ^ SyncRoot
        {
            Object ^ get() { return this; }
        }
    
        virtual void CopyTo(Array ^, int);
        virtual IEnumerator ^ GetEnumerator(void);
    };
  5. Open the RentalProperty.cpp source file and change it as follows:
       
    #include "Properties.h"
    
    CProperties::CProperties(void)
    {
        counter = 0;
        RentalProperties = gcnew array<Object ^>(5);
    }
    
    void CProperties::CopyTo(Array ^, int)
    {
    }
    
    IEnumerator ^ CProperties::GetEnumerator(void)
    {
        return nullptr;
    }
  6. Save all

The Size of a Collection

 

A Fixed-Size Collection

In the next sections, we will see how to add items to a collection. As you add or insert items in the list, the Count property grows. If your collection is array-based, when you start it, you specify the number of items that the list will contain. In theory, you cannot add new items beyond that number. In reality, you can increase the size of an array and then add a new item. If your collection is a linked list, you are also not confined to the laws of space (unless your computer runs out of memory.

If you create a list whose number of items must be constant, the user cannot add items beyond the maximum allowed number. Therefore, before adding an item, you can first check whether the collection has a fixed size or not. To give you this information, the IList interface is equipped with a Boolean read-only property named IsFxedSize. This property simply lets the user know whether the collection has a fixed number of items.

Here is an example of implementing this property:

public ref class CObjects : public IList
{
private:
    int items;
	array<Object ^> ^ objects;

public:
    . . . No Change

    virtual property bool IsFixedSize
    {
	bool get() { return false; }
    }

    virtual void CopyTo(Array ^, int);
    virtual IEnumerator ^ GetEnumerator(void);
};

Practical Learning Practical Learning: Implementing the IsFixedSize Property

A Read-Only Collection

Most collections are meant to receive new items. If you want, you can create a collection that cannot receive new values. To support this, the IList interface is equipped with the Boolean IsReadOnly property. If a collection is read-only, it would prevent the clients from adding items to it.

Here is an example of implementing the IsReadOnly property:

public ref class CObjects : public IList
{
private:
    int items;
	array<Object ^> ^ objects;

public:
    . . . No Change

    virtual property bool IsReadOnly
    {
	bool get() { return false; }
    }

    . . . No Change
};

Practical Learning Practical Learning: Implementing the IsReadOnly Property

  1. In the Properties.h header file, add the following property:
    #pragma once
    
    #include "RentalProperty.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CProperties : public IList
    {
    private:
        array<Object ^> ^ RentalProperties;
        int counter;
    	
    public:
        . . . No Change
    
        virtual property bool IsReadOnly
        {
    	bool get() { return false; }
        }
    
        virtual void CopyTo(Array ^, int);
        virtual IEnumerator ^ GetEnumerator(void);
    };
  2. In the Class View, right-click CProperties -> Add -> Function...
  3. Accept the Return Type as int and set the Function Name to Add
  4. In the Parameter Type, type Object ^
  5. In the Parameter Name, type value and click Add
  6. Click the virtual check box
     
  7. Click Finish
  8. In the Class View, right-click CProperties -> Add -> Function...
  9. Set the Return Type to void
  10. Set the Function Name to insert
  11. In the Parameter Type, select int
  12. In the Parameter Name, type index and click Add
  13. In the Parameter Type, type Object ^
  14. In the Parameter Name, type value and click Add
  15. Click the virtual check box
     
  16. Click Finish
  17. Open the Properties.h header file and add the following property
     
    #pragma once
    
    #include "RentalProperty.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CProperties : public IList
    {
    private:
        array<Object ^> ^ RentalProperties;
        int counter;
    	
    public:
        . . . No Change
    
        virtual property Object ^ default[int]
        {
    	Object ^ get(int index) { return nullptr; }
    	void set(int index, Object ^ value) { }
        }
    
        virtual void CopyTo(Array ^, int);
        virtual IEnumerator ^ GetEnumerator(void);
    
        . . . No Change
    };
  18. In the Class View, right-click CProperties -> Add -> Function...
  19. Set the Return Type to bool
  20. Set the Function Name to Contains
  21. In the Parameter Type, type Object ^
  22. In the Parameter Name, type value and click Add
  23. Click the virtual check box
     
  24. Click Finish
  25. In the Class View, right-click CProperties -> Add -> Function...
  26. Accept the Return Type as int and set the Function Name to IndexOf
  27. In the Parameter Type, type Object ^
  28. In the Parameter Name, type value and click Add
  29. Click the virtual check box
     
  30. Click Finish
  31. In the Class View, right-click CProperties -> Add -> Function...
  32. Set the Return Type to void
  33. Set the Function Name to RemoveAt
  34. In the Parameter Type, select int
  35. In the Parameter Name, type index and click Add
  36. Click the virtual check box
  37. Click Finish
  38. In the Class View, right-click CProperties -> Add -> Function...
  39. Set the Return Type to void
  40. Set the Function Name to Remove
  41. In the Parameter Type, select Object ^
  42. In the Parameter Name, type value and click Add
  43. Click the virtual check box
  44. Click Finish
  45. In the Class View, right-click CProperties -> Add -> Function...
  46. Set the Return Type to void
  47. Set the Function Name to Clear
  48. Click the virtual check box
  49. Click Finish
    #pragma once
    
    #include "RentalProperty.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CProperties : public IList
    {
    private:
        array<Object ^> ^ RentalProperties;
        int counter;
    	
    public:
        CProperties(void);
    
        virtual property int Count
        {
            int get() { return counter; }
        }
    
        virtual property bool IsSynchronized
        {
            bool get() { return false; }
        }
    
        virtual property Object ^ SyncRoot
        {
            Object ^ get() { return this; }
        }
    
        virtual property bool IsFixedSize
        {
    	bool get() { return false; }
        }
    
        virtual property bool IsReadOnly
        {
    	bool get() { return false; }
        }
    
        virtual property Object ^ default[int]
        {
    	Object ^ get(int index) { return nullptr; }
    	void set(int index, Object ^ value) { }
        }
    
        virtual void CopyTo(Array ^, int);
        virtual IEnumerator ^ GetEnumerator(void);
    
        // This method is used to add a new item to the collection
        virtual int Add(Object ^ value);
        // This method can be used to insert an item at 
        // a certain position inside the collection
        virtual void Insert(int index, Object ^ value);
        // This method is used to find out whether the item 
        //  passed as argument exists in the collection
        virtual bool Contains(Object ^ value);
        // This method is used to check whether the item passed as
        // argument exists in the collection. If so, it returns its index
        virtual int IndexOf(Object ^ value);
        // This method is used to delete the item positioned 
        // at the index passed as argument
        virtual void RemoveAt(int index);
        // This method first checks the existence of the item passed 
        //  as argument. If the item exists, the method deletes it
        virtual void Remove(Object ^ value);
        // This methods deletes all items from the collection
        virtual void Clear(void);
    };

Populating the Collection

 

Adding an Item

As it should be obvious, the primary operation to perform on a list is to populate it with at least one item. To support this, the IList interface is equipped with a method named Add. Its syntax is:

int Add(Object ^ value);

This method takes one argument as the object to add to the collection. If your collection is an array, you can first check that there is still enough room in the collection to add a new item. In reality, this is never an issue with the IList interface:

If the method succeeds with the addition, it returns the position where the value was added in the list. This is usually the last position in the list.

Here is an example:

public ref class CObjects : public IList
{
private:
    int items;
    array<Object ^> ^ objects;

public:
    . . . No Change

    virtual int Add(Object ^ value);
};

. . . No Change

int CObjects::Add(Object ^ value)
{
    // Check whether there is still room in
    // the array to add a new item
    if( items < objects->Length )
    {
        // Since there is room, put the new item to the end
	objects[items] = value;
	// increase the number of items
	items++;
	// Return the index of the item that was added
	return items - 1;
    } // Since the item could not be added, return a negative index
    else
	return -1;
}

Practical Learning Practical Learning: Adding an Item to the Collection

  1. In the Scopes combo box of the Code Editor, select CProperties and, in the Functions combo box, select Add
  2. Implement the method as follows:
     
    // This method is used to add a new item to the collection
    int CProperties::Add(Object ^ value)
    {
        // Find out if the array is getting too small for the next item(s)
        // If it is, increase its size by 5
        if( Count == RentalProperties->Length )
    	Array::Resize(customers, customers->Length + 5);
    
        if( counter < RentalProperties->Length )
        {
    	RentalProperties[counter] = value;
    	counter++;
    	return counter - 1;
        }
        else
    	return -1;
    }
  3. In the Class View, right-click CProperties -> Add -> Function...
  4. In the Return Type combo box, type CRentalProperty ^
  5. Set the Function Name to Get
  6. In the Parameter Type, select int
  7. In the Parameter Name, type index and click Add
     
  8. Click Finish
  9. Implement the method as follows:
     
    // This method is used to get the property positioned
    // at the index passed as argument
    CRentalProperty ^ CProperties::Get(int index)
    {
        return dynamic_cast<CRentalProperty ^>(RentalProperties[index]);
    }
  10. Open the Exercise.cpp source file and change it as follows:
     
    #include "RentalProperty.h"
    #include "Properties.h"
    
    using namespace System;
    
    int main()
    {
        CProperties ^ properties = gcnew CProperties;
        CRentalProperty ^ rental = nullptr;
    
        rental = gcnew CRentalProperty;
        rental->PropertyCode = 737495;
        rental->PropertyType = PropertyTypes::Apartment;
        rental->PropertyCondition = PropertyConditions::Good;
        rental->Bedrooms = 1;
        rental->Bathrooms = 1;
        rental->MonthlyRent = 950.00;
        properties->Add(rental);
    
        rental = gcnew CRentalProperty;
        rental->PropertyCode = 293749;
        rental->PropertyType = PropertyTypes::SingleFamily;
        rental->PropertyCondition = PropertyConditions::Excellent;
        rental->Bedrooms = 5;
        rental->Bathrooms = 3.5;
        rental->MonthlyRent = 2550.75;
        properties->Add(rental);
    
        rental = gcnew CRentalProperty;
        rental->PropertyCode = 224006;
        rental->PropertyType = PropertyTypes::Apartment;
        rental->PropertyCondition = PropertyConditions::Excellent;
        rental->Bedrooms = 2;
        rental->Bathrooms = 1;
        rental->MonthlyRent = 1250.55;
        properties->Add(rental);
    
        rental = gcnew CRentalProperty;
        rental->PropertyCode = 197249;
        rental->PropertyType = PropertyTypes::Townhouse;
        rental->PropertyCondition = PropertyConditions::BadShape;
        rental->Bedrooms = 4;
        rental->Bathrooms = 2.5;
        rental->MonthlyRent = 1750.65;
        properties->Add(rental);
    
        Console::WriteLine(L"<+> Solas Properties Rental <+>");
        Console::WriteLine(L"<->   Properties Listing    <->");
        for(int i = 0; i < properties->Count; i++)
        {
    	Console::WriteLine(L"---------------------------");
    	Console::WriteLine(L"{0}. Property Details",
                            (i+1).ToString());
    	Console::WriteLine(L"Property #:    {0}",
    			properties->Get(i)->PropertyCode);
    	Console::WriteLine(L"Property Type: {0}",
    			properties->Get(i)->PropertyType);
    	Console::WriteLine(L"Condition:     {0}",
    			properties->Get(i)->PropertyCondition);
    	Console::WriteLine(L"Bedrooms:      {0}",
    			properties->Get(i)->Bedrooms);
    	Console::WriteLine(L"Bathrooms:     {0}",
    			properties->Get(i)->Bathrooms);
    	Console::WriteLine(L"Monthly Rent:  {0}",
    			properties->Get(i)->MonthlyRent);
        }
        Console::WriteLine(L"================================");
        return 0;
    }
  11. Execute the application to see the result
     
    <+> Solas Properties Rental <+>
    <->   Properties Listing    <->
    ---------------------------
    1. Property Details
    Property #:    737495
    Property Type: Apartment
    Condition:     Good
    Bedrooms:      1
    Bathrooms:     1
    Monthly Rent:  950
    ---------------------------
    2. Property Details
    Property #:    293749
    Property Type: SingleFamily
    Condition:     Excellent
    Bedrooms:      5
    Bathrooms:     3.5
    Monthly Rent:  2550.75
    ---------------------------
    3. Property Details
    Property #:    224006
    Property Type: Apartment
    Condition:     Excellent
    Bedrooms:      2
    Bathrooms:     1
    Monthly Rent:  1250.55
    ---------------------------
    4. Property Details
    Property #:    197249
    Property Type: Townhouse
    Condition:     BadShape
    Bedrooms:      4
    Bathrooms:     2.5
    Monthly Rent:  1750.65
    ================================
    Press any key to continue . . .
  12. Close the DOS window and return to your programming environment

Inserting an Item

When you call the IList::Add() method, it adds the new item to the end of the list. Sometimes, you will want the new item to be insert somewhere inside the list. To support this operation, the IList interface provides a method named Insert. Its syntax is:

void Insert(int index, Object^ value);

This method takes two arguments. The second argument is the object that will be inserted into the list. The argument must hold a valid value. Because this method takes an Object handle, if your collection is using a different type of item, you may have to cast it to Object. The first argument is the index of the item that will precede the new one.

As mentioned for the Add() method, there are a few things you should know about this operation success or lack of it:

Practical Learning Practical Learning: Inserting an Item in the Collection

  1. Access the Properties.cpp source file.
    In the Scopes combo box of the Code Editor, select CProperties and, in the Functions combo box, select Insert
  2. Implement the Insert() method as follows:
     
    // This method can be used to insert an item at a 
    // certain position inside the collection
    void CProperties::Insert(int index, Object ^ value)
    {
        if( (counter <= RentalProperties->Length) &&
    	(index < Count) &&
    	(index >= 0) )
        {
            counter++;
    
    	for(int i = Count - 1; i > index; i--)
    		RentalProperties[i] = RentalProperties[i - 1];
    	RentalProperties[index] = value;
        }
    }
  3. Open the Exercise.cpp source file and change it as follows:
     
    #include "RentalProperty.h"
    #include "Properties.h"
    
    using namespace System;
    
    int main()
    {
        CProperties ^ properties = gcnew CProperties;
        CRentalProperty ^ rental = nullptr;
    
        . . . No Change
    	
        rental = gcnew CRentalProperty;
        rental->PropertyCode = 592795;
        rental->PropertyType = PropertyTypes::SingleFamily;
    	rental->PropertyCondition = PropertyConditions::Good;
        rental->Bedrooms = 3;
        rental->Bathrooms = 2.00;
        rental->MonthlyRent = 1870.35;
        properties->Insert(2, rental);
    
        Console::WriteLine(L"<+> Solas Properties Rental <+>");
        Console::WriteLine(L"<->   Properties Listing    <->");
        for(int i = 0; i < properties->Count; i++)
        {
    	Console::WriteLine(L"---------------------------");
    	Console::WriteLine(L"{0}. Property Details",
                            (i+1).ToString());
    	Console::WriteLine(L"Property #:    {0}",
    			properties->Get(i)->PropertyCode);
    	Console::WriteLine(L"Property Type: {0}",
    			properties->Get(i)->PropertyType);
    	Console::WriteLine(L"Condition:     {0}",
    			properties->Get(i)->PropertyCondition);
    	Console::WriteLine(L"Bedrooms:      {0}",
    			properties->Get(i)->Bedrooms);
    	Console::WriteLine(L"Bathrooms:     {0}",
    			properties->Get(i)->Bathrooms);
    	Console::WriteLine(L"Monthly Rent:  {0}",
    			properties->Get(i)->MonthlyRent);
        }
        Console::WriteLine(L"================================");
        return 0;
    }
  4. Execute the application to see the result
     
    <+> Solas Properties Rental <+>
    <->   Properties Listing    <->
    ---------------------------
    1. Property Details
    Property #:    737495
    Property Type: Apartment
    Condition:     Good
    Bedrooms:      1
    Bathrooms:     1
    Monthly Rent:  950
    ---------------------------
    2. Property Details
    Property #:    293749
    Property Type: SingleFamily
    Condition:     Excellent
    Bedrooms:      5
    Bathrooms:     3.5
    Monthly Rent:  2550.75
    ---------------------------
    3. Property Details
    Property #:    592795
    Property Type: SingleFamily
    Condition:     Good
    Bedrooms:      3
    Bathrooms:     2
    Monthly Rent:  1870.35
    ---------------------------
    4. Property Details
    Property #:    224006
    Property Type: Apartment
    Condition:     Excellent
    Bedrooms:      2
    Bathrooms:     1
    Monthly Rent:  1250.55
    ---------------------------
    5. Property Details
    Property #:    197249
    Property Type: Townhouse
    Condition:     BadShape
    Bedrooms:      4
    Bathrooms:     2.5
    Monthly Rent:  1750.65
    ================================
    Press any key to continue . . .
  5. Close the DOS window and return to your programming environment

Locating an Item in the Collection

 

This Default Item of the Collection

While using a collection, various operations require that you know the object you are currently accessing. To provide this operation, you must create an indexed property. This property should take an index and return the type of object that makes up the collection. Here is an example:

using namespace System;
using namespace System::Collections;

public ref class CObjects : public IList
{
private:
    int items;
    array<Object ^> ^ objects;

public:
    . . . No Change

    virtual property Object ^ default[int]
    {
        Object ^ get(int index) { return objects[index]; }

        void set(int index, Object ^ value)
        {
            objects[index] = value;
        }
    }

    . . . No Change
};

After creating this property, you can then access an item using its index and applying the [] operator on its instance. Remember that if you want to use for each, you must appropriately implement the IEnumerable::GetEnumerator() method.

Practical Learning Practical Learning: Identifying this Item in the Collection

  1. Access the Properties.h header file
  2. In the Scopes combo box of the Code Editor, select CProperties::default
  3. In the Functions combo box, select get
  4. Change the default property as follows:
     
    #pragma once
    
    #include "RentalProperty.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CProperties : public IList
    {
    private:
        array<Object ^> ^ RentalProperties;
        int counter;
    	
    public:
        . . . No Change
    
        virtual property Object ^ default[int]
        {
    	Object ^ get(int index) { return RentalProperties[index]; }
    	void set(int index, Object ^ value)
    	{
    	    RentalProperties[index] = value;
    	}
        }
    
        . . . No Change
    };
  5. Access the Exercise.cpp source file and change the section of the for loop as follows:
    #include "RentalProperty.h"
    #include "Properties.h"
    
    using namespace System;
    
    int main()
    {
        . . . No Change
    
        Console::WriteLine(L"<+> Solas Properties Rental <+>");
        Console::WriteLine(L"<->   Properties Listing    <->");
        for(int i = 0; i < properties->Count; i++)
        {
            CRentalProperty ^ prop = dynamic_cast<CRentalProperty ^>(properties[i]);
    	Console::WriteLine(L"---------------------------");
    	Console::WriteLine(L"{0}. Property Details",
                            (i+1).ToString());
    	Console::WriteLine(L"Property #:    {0}",
    			prop->PropertyCode);
    	Console::WriteLine(L"Property Type: {0}",
    			prop->PropertyType);
    	Console::WriteLine(L"Condition:     {0}",
    			prop->PropertyCondition);
    	Console::WriteLine(L"Bedrooms:      {0}",
    			prop->Bedrooms);
    	Console::WriteLine(L"Bathrooms:     {0}",
    			prop->Bathrooms);
    	Console::WriteLine(L"Monthly Rent:  {0}",
    			prop->MonthlyRent);
        }
        Console::WriteLine(L"================================");
        return 0;
    }
  6. Execute the application to see the result
  7. Close the DOS window
  8. Open the Properties.h header file
  9. To be able to use for each, make the following changes:
    #pragma once
    
    #include "RentalProperty.h"
    
    using namespace System;
    using namespace System::Collections;
    
    public ref class CProperties : public IList, IEnumerator
    {
    private:
        array<Object ^> ^ RentalProperties;
        int counter;
        int cur;
    	
    public:
        CProperties(void);
    
        virtual property int Count
        {
            int get() { return counter; }
        }
    
        virtual property bool IsSynchronized
        {
            bool get() { return false; }
        }
    
        virtual property Object ^ SyncRoot
        {
            Object ^ get() { return this; }
        }
    
        virtual property bool IsFixedSize
        {
    	bool get() { return false; }
        }
    
        virtual property bool IsReadOnly
        {
    	bool get() { return false; }
        }
    
        virtual property Object ^ default[int]
        {
    	Object ^ get(int index) { return RentalProperties[index]; }
    	void set(int index, Object ^ value)
    	{
    	    RentalProperties[index] = value;
    	}
        }
    
        property Object ^ Current
        {
            virtual Object ^ get()
            {
                try {
                    return this[cur];
                }
                catch(IndexOutOfRangeException ^)
                {
                    Console::WriteLine(L"The current rental property can be "
                                       L"accessed only within a valid range ");
                    return nullptr;
                }
            }
        }
    
        virtual void Reset();
        virtual bool MoveNext();
    
        virtual void CopyTo(Array ^, int);
        virtual IEnumerator ^ GetEnumerator(void);
    
        . . . No Change
    };
  10. Open the Properties.cpp source file and make the following changes:
    #include "Properties.h"
    
    CProperties::CProperties(void)
        : counter(0), cur(-1)
    {
        RentalProperties = gcnew array<Object ^>(5);
    }
    
    void CProperties::CopyTo(Array ^, int)
    {
    }
    
    void CProperties::Reset()
    {
        cur = -1;
    }
    bool CProperties::MoveNext()
    {
        cur++;
    
        if( cur < Count )
            return true;
        else
            return false;
    }
    
    IEnumerator ^ CProperties::GetEnumerator(void)
    {
        return this;
    }
    
    . . . No Change
  11. Open the Exercise.cpp source file and make the following changes:
    #include "RentalProperty.h"
    #include "Properties.h"
    
    using namespace System;
    
    int main()
    {
        . . . No Change
    
        int i = 1;
        Console::WriteLine(L"<+> Solas Properties Rental <+>");
        Console::WriteLine(L"<->   Properties Listing    <->");
        for each(CRentalProperty ^ prop in properties)
        {
    	Console::WriteLine(L"---------------------------");
    	Console::WriteLine(L"{0}. Property Details", i.ToString());
    	Console::WriteLine(L"Property #:    {0}",
    			prop->PropertyCode);
    	Console::WriteLine(L"Property Type: {0}",
    			prop->PropertyType);
    	Console::WriteLine(L"Condition:     {0}",
    			prop->PropertyCondition);
    	Console::WriteLine(L"Bedrooms:      {0}",
    			prop->Bedrooms);
    	Console::WriteLine(L"Bathrooms:     {0}",
    			prop->Bathrooms);
    	Console::WriteLine(L"Monthly Rent:  {0}",
    			prop->MonthlyRent);
    	i++;
        }
        Console::WriteLine(L"================================");
        return 0;
    }
  12. Close the DOS window
  13. Checking the Existence of an Item

    One of the routine operations you can perform on a list is to find out whether it contains a certain item. To assist you with this operation, the IList interface is equipped with a method named Contains. Its syntax is:

    bool Contains(Object ^ item);

    This method takes as argument the item to look for. If the item is found in the list, the method returns true. If no item is found in the collection, this method returns false.

    Here is an example of implementing this method:

    public ref class CObjects : public IList
    {
    private:
        int items;
        array<Object ^> ^ objects;
    
    public:
        . . . No Change
    
        virtual int Add(Object ^);
        virtual void Insert(int, Object ^);
        virtual bool Contains(Object ^);
    };
    
    . . . No Change
    
    bool CObjects::Contains(Object ^ value)
    {
        for(int i = 0; i < Count; i++
    	if( objects[i] == value )
    	    return true;
        return false;
    }

    This method calls the Equals() method of the objects that make up the collection (in our example, that would be the objects array) to find out whether the item argument exists in the collection. If this method produces a wrong result especially if you are using your own class to represent the item, you may have to override your own Equals() method.

    Practical Learning Practical Learning: Checking the Existence of an Item in the Collection

    1. Open the RentalProperty.h header file and declare a virtual Equals() method as follows:
       
      #pragma once
      
      using namespace System;
      
      . . . No Change
      
      [Serializable]
      public ref class CRentalProperty
      {
      private:
          . . . No Change
      
      public:
          . . . No Change
      
      public:
          virtual bool Equals(CRentalProperty ^);
      
          // This constructor is used to create 
          // default values for a property
      	CRentalProperty(void);
      };
    2. Access the RentalProperty.cpp source file and implement the method as follows:
      #include "RentalProperty.h"
      
      CRentalProperty::CRentalProperty(void)
      {
          propCode = 0;
          type     = PropertyTypes::Unknown;
          cond     = PropertyConditions::Unknown;
          beds     = 0;
          baths    = 0.0;
          val      = 0.00;
      }
      
      bool CRentalProperty::Equals(CRentalProperty ^ prop)
      {
          if( (propCode == prop->PropertyCode) &&
      	(type     == prop->PropertyType) &&
      	(cond     == prop->PropertyCondition) &&
      	(beds     == prop->Bedrooms) &&
      	(baths    == prop->Bathrooms) &&
      	(val      == prop->MonthlyRent) )
      	return true;
          else
      	return false;
      }
    3. Open the Properties.cpp source file
    4. In the Functions combo box, select Contains and implement the method as follows:
      // This method is used to find out whether the item
      // passed as argument exists in the collection
      bool CProperties::Contains(Object ^ value)
      {
          bool found = false;
      
          for(int i = 0; i < Count; i++)
      	if( dynamic_cast<CRentalProperty ^>(
      	   this[i])->Equals(dynamic_cast<CRentalProperty ^>(value)) )
      		found = true;
      
          return found;
      }
    5. Open the Exercise.cpp source file and make the following changes:
      #include "RentalProperty.h"
      #include "Properties.h"
      
      using namespace System;
      
      int main()
      {
          CProperties ^ properties = gcnew CProperties;
          CRentalProperty ^ rental = nullptr;
      
          rental = gcnew CRentalProperty;
          rental->PropertyCode = 737495;
          rental->PropertyType = PropertyTypes::Apartment;
          rental->PropertyCondition = PropertyConditions::Good;
          rental->Bedrooms = 1;
          rental->Bathrooms = 1;
          rental->MonthlyRent = 950.00;
          properties->Add(rental);
      
          rental = gcnew CRentalProperty;
          rental->PropertyCode = 293749;
          rental->PropertyType = PropertyTypes::SingleFamily;
          rental->PropertyCondition = PropertyConditions::Excellent;
          rental->Bedrooms = 5;
          rental->Bathrooms = 3.5;
          rental->MonthlyRent = 2550.75;
          properties->Add(rental);
      
          rental = gcnew CRentalProperty;
          rental->PropertyCode = 224006;
          rental->PropertyType = PropertyTypes::Apartment;
          rental->PropertyCondition = PropertyConditions::Excellent;
          rental->Bedrooms = 2;
          rental->Bathrooms = 1;
          rental->MonthlyRent = 1250.55;
          properties->Add(rental);
      
          rental = gcnew CRentalProperty;
          rental->PropertyCode = 197249;
          rental->PropertyType = PropertyTypes::Townhouse;
          rental->PropertyCondition = PropertyConditions::BadShape;
          rental->Bedrooms = 4;
          rental->Bathrooms = 2.5;
          rental->MonthlyRent = 1750.65;
          properties->Add(rental);
      	
          rental = gcnew CRentalProperty;
          rental->PropertyCode = 592795;
          rental->PropertyType = PropertyTypes::SingleFamily;
      	rental->PropertyCondition = PropertyConditions::Good;
          rental->Bedrooms = 3;
          rental->Bathrooms = 2.00;
          rental->MonthlyRent = 1870.35;
          properties->Add(rental);
      
          int i = 1;
          Console::WriteLine(L"<+> Solas Properties Rental <+>");
          Console::WriteLine(L"<->   Properties Listing    <->");
          for each(CRentalProperty ^ prop in properties)
          {
      	Console::WriteLine(L"---------------------------");
      	Console::WriteLine(L"{0}. Property Details", i.ToString());
      	Console::WriteLine(L"Property #:    {0}",
      			prop->PropertyCode);
      	Console::WriteLine(L"Property Type: {0}",
      			prop->PropertyType);
      	Console::WriteLine(L"Condition:     {0}",
      			prop->PropertyCondition);
      	Console::WriteLine(L"Bedrooms:      {0}",
      			prop->Bedrooms);
      	Console::WriteLine(L"Bathrooms:     {0}",
      			prop->Bathrooms);
      	Console::WriteLine(L"Monthly Rent:  {0}",
      			prop->MonthlyRent);
      	i++;
          }
          Console::WriteLine(L"================================");
      
          CRentalProperty ^ item1 = gcnew CRentalProperty;
          item1->PropertyCode = 293749;
          item1->PropertyType = PropertyTypes::SingleFamily;
          item1->PropertyCondition = PropertyConditions::Excellent;
          item1->Bedrooms = 5;
          item1->Bathrooms = 3.5;
          item1->MonthlyRent = 2550.75;
      
          Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
          Console::WriteLine(L"-=- Sample Property -=-");
          Console::WriteLine(L"Property #:    {0}",
      			item1->PropertyCode);
          Console::WriteLine(L"Property Type: {0}",
      			item1->PropertyType);
          Console::WriteLine(L"Condition:     {0}",
      			item1->PropertyCondition);
          Console::WriteLine(L"Bedrooms:      {0}",
      			item1->Bedrooms);
          Console::WriteLine(L"Bathrooms:     {0}",
      			item1->Bathrooms);
          Console::WriteLine(L"Monthly Rent:  {0}",
      			item1->MonthlyRent);
      
          Console::WriteLine(L"-------------------------------------------");
          if( properties->Contains(item1) == true )
      Console::WriteLine("That property already exists in the listing");
          else
      Console::WriteLine("The property was not found in our database");
      
          Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
      
          CRentalProperty ^ item2 = gcnew CRentalProperty;
          item2->PropertyCode = 290004;
          item2->PropertyType = PropertyTypes::SingleFamily;
          item2->PropertyCondition = PropertyConditions::Excellent;
          item2->Bedrooms = 5;
          item2->Bathrooms = 3.5;
          item1->MonthlyRent = 2550.75;
      
          Console::WriteLine(L"-=- Sample Property -=-");
          Console::WriteLine(L"Property #:    {0}",
      			item2->PropertyCode);
          Console::WriteLine(L"Property Type: {0}",
      			item2->PropertyType);
          Console::WriteLine(L"Condition:     {0}",
      			item2->PropertyCondition);
          Console::WriteLine(L"Bedrooms:      {0}",
      			item2->Bedrooms);
          Console::WriteLine(L"Bathrooms:     {0}",
      			item2->Bathrooms);
          Console::WriteLine(L"Monthly Rent:  {0}",
      			item2->MonthlyRent);
      
          Console::WriteLine(L"-------------------------------------------");
          if( properties->Contains(item2) == true )
      Console::WriteLine("That property already exists in the listing");
          else
      Console::WriteLine("The property was not found in our database");
          Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
      
          return 0;
      }
    6. Execute the application to see the result: 
      <+> Solas Properties Rental <+>
      <->   Properties Listing    <->
      ---------------------------
      1. Property Details
      Property #:    737495
      Property Type: Apartment
      Condition:     Good
      Bedrooms:      1
      Bathrooms:     1
      Monthly Rent:  950
      ---------------------------
      2. Property Details
      Property #:    293749
      Property Type: SingleFamily
      Condition:     Excellent
      Bedrooms:      5
      Bathrooms:     3.5
      Monthly Rent:  2550.75
      ---------------------------
      3. Property Details
      Property #:    224006
      Property Type: Apartment
      Condition:     Excellent
      Bedrooms:      2
      Bathrooms:     1
      Monthly Rent:  1250.55
      ---------------------------
      4. Property Details
      Property #:    197249
      Property Type: Townhouse
      Condition:     BadShape
      Bedrooms:      4
      Bathrooms:     2.5
      Monthly Rent:  1750.65
      ---------------------------
      5. Property Details
      Property #:    592795
      Property Type: SingleFamily
      Condition:     Good
      Bedrooms:      3
      Bathrooms:     2
      Monthly Rent:  1870.35
      ================================
      8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
      -=- Sample Property -=-
      Property #:    293749
      Property Type: SingleFamily
      Condition:     Excellent
      Bedrooms:      5
      Bathrooms:     3.5
      Monthly Rent:  2550.75
      -------------------------------------------
      That property already exists in the listing
      8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
      -=- Sample Property -=-
      Property #:    290004
      Property Type: SingleFamily
      Condition:     Excellent
      Bedrooms:      5
      Bathrooms:     3.5
      Monthly Rent:  0
      -------------------------------------------
      The property was not found in our database
      8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
      Press any key to continue . . .
    7. Close the DOS window
    8. Getting the Index of an Item

      The Contains method is used to check whether a particular item (already) exists in the collection. If you know that a certain item exists in the collection but you don't know its index inside the list, the IList interface can assist you through a method named IndexOf. Its syntax is:

      int IndexOf(Object^ value);

      This method takes as argument the item to look for in the list. If the item is found in the collection, the method returns its index. If there is no item defined like that, the method returns -1. Here is an example of implementing this method:

      using namespace System;
      using namespace System::Collections;
      
      public ref class CObjects : public IList
      {
      private:
          int items;
          array<Object ^> ^ objects;
      
      public:
      
          . . . No Change
      
          virtual int IndexOf(Object ^);
      };
      
      . . . No Change
      
      int CObjects::IndexOf(Object ^ value)
      {
          for(int i = 0; i < Count; i++
      	if( objects[i] == value )
      	    return i;
          return -1;
      }

      This method calls the Equals() method of the objects that make up the collection (in our example, that would be the objects array) to find out whether the item argument exists in the collection. If this method produces a wrong result especially if you are using your own class to represent the item, you may have to override your own Equals() method.

      Practical Learning Practical Learning: Getting the Index of an Item

      1. Open the Properties.cpp source file.
        In the Functions combo box, select IndexOf and implement the method as follows:
        // This method is used to check whether the item passed as 
        // argument exists in the collection. If so, it returns its index
        int CProperties::IndexOf(Object ^ value)
        {
            int custIndex = -1;
        
            for(int i = 0; i < Count; i++)
            {
        	if( dynamic_cast<CRentalProperty ^>(
        	  this[i])->Equals(dynamic_cast<CRentalProperty ^>(value)) )
        	{
        	    custIndex = i;
        	    break;
        	}
            }
        
            return custIndex;
        }
      2. Open the Exercise.cpp source file and make the following changes:
        #include "RentalProperty.h"
        #include "Properties.h"
        
        using namespace System;
        
        int main()
        {
            . . . No Change
            Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
        
            CRentalProperty ^ item3 = gcnew CRentalProperty;
            item3->PropertyCode = 224006;
            item3->PropertyType = PropertyTypes::Apartment;
            item3->PropertyCondition = PropertyConditions::Excellent;
            item3->Bedrooms = 2;
            item3->Bathrooms = 1;
            item3->MonthlyRent = 1250.55;
        
            Console::WriteLine(L"-=- Sample Property -=-");
            Console::WriteLine(L"Property #:    {0}",
        			item3->PropertyCode);
            Console::WriteLine(L"Property Type: {0}",
        			item3->PropertyType);
            Console::WriteLine(L"Condition:     {0}",
        			item3->PropertyCondition);
            Console::WriteLine(L"Bedrooms:      {0}",
        			item3->Bedrooms);
            Console::WriteLine(L"Bathrooms:     {0}",
        			item3->Bathrooms);
            Console::WriteLine(L"Monthly Rent:  {0}",
        			item3->MonthlyRent);
            Console::WriteLine(L"The index of this property is: {0}",
            properties->IndexOf(item3));
            Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
            return 0;
        }
      3. Execute the application to see the result: 
        <+> Solas Properties Rental <+>
        <->   Properties Listing    <->
        ---------------------------
        1. Property Details
        Property #:    737495
        Property Type: Apartment
        Condition:     Good
        Bedrooms:      1
        Bathrooms:     1
        Monthly Rent:  950
        ---------------------------
        2. Property Details
        Property #:    293749
        Property Type: SingleFamily
        Condition:     Excellent
        Bedrooms:      5
        Bathrooms:     3.5
        Monthly Rent:  2550.75
        ---------------------------
        3. Property Details
        Property #:    224006
        Property Type: Apartment
        Condition:     Excellent
        Bedrooms:      2
        Bathrooms:     1
        Monthly Rent:  1250.55
        ---------------------------
        4. Property Details
        Property #:    197249
        Property Type: Townhouse
        Condition:     BadShape
        Bedrooms:      4
        Bathrooms:     2.5
        Monthly Rent:  1750.65
        ---------------------------
        5. Property Details
        Property #:    592795
        Property Type: SingleFamily
        Condition:     Good
        Bedrooms:      3
        Bathrooms:     2
        Monthly Rent:  1870.35
        ================================
        8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
        -=- Sample Property -=-
        Property #:    293749
        Property Type: SingleFamily
        Condition:     Excellent
        Bedrooms:      5
        Bathrooms:     3.5
        Monthly Rent:  2550.75
        -------------------------------------------
        That property already exists in the listing
        8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
        -=- Sample Property -=-
        Property #:    290004
        Property Type: SingleFamily
        Condition:     Excellent
        Bedrooms:      5
        Bathrooms:     3.5
        Monthly Rent:  0
        -------------------------------------------
        The property was not found in our database
        8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
        -=- Sample Property -=-
        Property #:    224006
        Property Type: Apartment
        Condition:     Excellent
        Bedrooms:      2
        Bathrooms:     1
        Monthly Rent:  1250.55
        The index of this property is: 2
        8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
        Press any key to continue . . .
      4. Close the DOS window
      5. Deleting Items in the Collection

         

        Deleting an Item by its Index

        If an item is not necessary in your list, you can delete it. Probably the simplest way to delete an item is to specify its position in the collection. To support this operation, the IList interface provides a method named RemoveAt. Its syntax is:

        void RemoveAt(int index);

        This method takes as argument the index of the item to be removed. Here is an example:

        public ref class CObjects : public IList
        {
        private:
            int items;
            array<Object ^> ^ objects;
        
        public:
            . . . No Change
            virtual void RemoveAt(int);
        };
        
        . . . No Change
        
        void CObjects::RemoveAt(int index)
        {
            if( (index >= 0) && (index < Count) )
            {
                for(int i = index; i < Count - 1; i++)
        	        objects[i] = objects[i + 1];
            	items--;
            }
        }

        Deleting an Item by its Value

        The problem with deleting an item based on its index is that, if you are not sure, you could delete the wrong item. An alternative is to first precisely define the item you want to get rid it, and then hand the item itself to the compiler that would remove it. To support this approach, the IList interface is equipped with a method named Remove() and whose syntax is:

        void Remove(Object^ value);

        This method takes as argument the item to be deleted. This means that the compiler will first look for the item in the list. If it finds that item, it removes it. If there is no item like value, nothing happens (the compiler doesn't throw an exception. Here is an example of implementing this method:

        public ref class CObjects : public IList
        {
        private:
            int items;
        	array<Object ^> ^ objects;
        
        public:
            . . . No Change
            virtual void Remove(Object ^);
        };
        
        . . . No Change
        
        void CObjects::Remove(Object ^ value)
        {
            RemoveAt(IndexOf(value));    
        }

        Clearing a Collection

        To remove all items from a list at once, you can implement Clear() method of the IList interface. Its syntax is:

        void Clear();

        Here is an example of implementing it:

        using namespace System;
        using namespace System::Collections;
        
        public ref class CObjects : public IList
        {
        private:
            int items;
        	array<Object ^> ^ objects;
        
        public:
            CObjects();
        
            virtual property int Count
            {
                int get() { return items; }
            }
        
            virtual property bool IsSynchronized
            {
        	bool get() { return false; }
            }
        
            virtual property Object ^ SyncRoot
            {
        	Object ^ get() { return this; }
            }
        
            virtual property bool IsFixedSize
            {
        	bool get() { return false; }
        	}
        
            virtual property bool IsReadOnly
            {
        	bool get() { return false; }
            }
        
            virtual property Object ^ default[int]
            {
                Object ^ get(int index) { return objects[index]; }
        
                void set(int index, Object ^ value)
                {
                    objects[index] = value;
                }
            }
        
            virtual void CopyTo(Array ^, int);
            virtual IEnumerator ^ GetEnumerator(void);
        
            virtual int  Add(Object ^);
            virtual void Insert(int, Object ^);
            virtual bool Contains(Object ^);
            virtual int  IndexOf(Object ^);
            virtual void RemoveAt(int);
            virtual void Remove(Object ^);
            virtual void Clear();
        };
        
        CObjects::CObjects()
        {
            items = 0;
            objects = gcnew array<Object ^>(5);
        }
        
        IEnumerator ^ CObjects::GetEnumerator(void)
        {
            return nullptr;
        }
        
        void CObjects::CopyTo(Array ^ ary, int index)
        {
        
        }
        
        int CObjects::Add(Object ^ value)
        {
            // Check whether there is still room in
            // the array to add a new item
            if( items < objects->Length )
            {
                // Since there is room, put the new item to the end
        	objects[items] = value;
        	// increase the number of items
        	items++;
        	// Return the index of the item that was added
        	return items - 1;
            } // Since the item could not be added, return a negative index
            else
        	return -1;
        }
        
        void CObjects::Insert(int index, Object ^ value)
        {
            // Just to be safe, make sure that
            // 1. There is still room in the array for a new item
            // 2. The index argument is lower than the current number of items
            // 3. The index argument is not negative
            if( (index >= 0) && (index < items) )
            {
        	// Before inserting the new item, create room for it
        	for(int i = items; i > index - 1; i--)
        		objects[i+1] = objects[i];
        	// Put the new item in the space that was created
        	objects[index] = value;
                // Since a new item has been added, increase the count
                items++;
            }
        }
        
        bool CObjects::Contains(Object ^ value)
        {
            for(int i = 0; i < Count; i++)
                if( objects[i] == value )
        	        return true;
            return false;
        }
        
        int CObjects::IndexOf(Object ^ value)
        {
            for(int i = 0; i < Count; i++)
                if( objects[i] == value )
                    return i;
            return -1;
        }
        
        void CObjects::RemoveAt(int index)
        {
            if( (index >= 0) && (index < Count) )
            {
                for(int i = index; i < Count - 1; i++)
        	        objects[i] = objects[i + 1];
            	items--;
            }
        }
        
        void CObjects::Remove(Object ^ value)
        {
            RemoveAt(IndexOf(value));
        }
        
        void CObjects::Clear()
        {
            items = 0;
        }
        
        int main()
        {
            CObjects ^ collNames = gcnew CObjects;
            String ^ name;
        	
            name = L"Anne Salmon";
            collNames->Add(name);
            name = L"Faustin Elmes";
            collNames->Add(name);
            name = L"Julius Pullman";
            collNames->Add(name);
            name = L"Bertrand Alexander";
            collNames->Add(name);
            name = L"Christian Voulzy";
            collNames->Add(name);
            name = L"Joan Lamm";
            collNames->Add(name);
        
            Console::WriteLine(L"Original List");
            for(int i = 0; i < collNames->Count; i++)
        	Console::WriteLine(L"{0}", collNames[i]);
        
            Console::WriteLine(L"<-><-><-><-><-><-><-><->");
            name = L"Christian E. Voulzy";
            if( collNames->Contains(name) )
        	Console::WriteLine(L"The item was found");
            else
        	Console::WriteLine(L"The item was not found");
        
            Console::WriteLine(L"<-><-><-><-><-><-><-><->");
            name = L"Bertrand Alexander";
            int index = collNames->IndexOf(name);
            if( index >= 0 )
        	Console::WriteLine(L"The index of Bertrand Alexander is {0}", index);
            else
        	Console::WriteLine(L"The item was not found");
        
            Console::WriteLine(L"<-><-><-><-><-><-><-><->");
            collNames->RemoveAt(2);
            Console::WriteLine(L"After deleting an item");
            for(int i = 0; i < collNames->Count; i++)
        	Console::WriteLine(L"{0}", collNames[i]);
        
            Console::WriteLine(L"<-><-><-><-><-><-><-><->");
            name = L"Faustin Elmes";
            collNames->Remove(name);
            Console::WriteLine(L"After deleting an item");
            for(int i = 0; i < collNames->Count; i++)
        	Console::WriteLine(L"{0}", collNames[i]);
        
            Console::WriteLine(L"<-><-><-><-><-><-><-><->");
            collNames->Clear();
            Console::WriteLine(L"After removing all items");
            for(int i = 0; i < collNames->Count; i++)
        	Console::WriteLine(L"{0}", collNames[i]);
        
            return 0;
        }

        This would produce:

        Original List
        Anne Salmon
        Faustin Elmes
        Julius Pullman
        Bertrand Alexander
        Christian Voulzy
        <-><-><-><-><-><-><-><->
        The item was not found
        <-><-><-><-><-><-><-><->
        The index of Bertrand Alexander is 3
        <-><-><-><-><-><-><-><->
        After deleting an item
        Anne Salmon
        Faustin Elmes
        Bertrand Alexander
        Christian Voulzy
        <-><-><-><-><-><-><-><->
        After deleting an item
        Anne Salmon
        Bertrand Alexander
        Christian Voulzy
        <-><-><-><-><-><-><-><->
        After removing all items
        Press any key to continue . . .

        Practical Learning Practical Learning: Removing Some Items From the Collection

        1. Access the Properties.cpp source file
        2. Implement the Remove(), the RemoveAt(), and the Clear() methods as follows:
          #include "Properties.h"
          
          CProperties::CProperties(void)
          	: counter(0), cur(-1)
          {
              RentalProperties = gcnew array<Object ^>(5);
          }
          
          void CProperties::CopyTo(Array ^, int)
          {
          }
          
          void CProperties::Reset()
          {
              cur = -1;
          }
          bool CProperties::MoveNext()
          {
              cur++;
          
              if( cur < Count )
                  return true;
              else
                  return false;
          }
          
          IEnumerator ^ CProperties::GetEnumerator(void)
          {
              return this;
          }
          
          // This method is used to add a new item to the collection
          int CProperties::Add(Object ^ value)
          {
              // Find out if the array is getting too small for the next item(s)
              // If it is, increase its size by 5
              if( Count == RentalProperties->Length )
          	Array::Resize(RentalProperties, RentalProperties->Length + 5);
          
              if( counter < RentalProperties->Length )
              {
          	RentalProperties[counter] = value;
          	counter++;
          	return counter - 1;
              }
              else
          	return -1;
          }
          
          // This method can be used to insert an item at a 
          // certain position inside the collection
          void CProperties::Insert(int index, Object ^ value)
          {
              if( (counter <= RentalProperties->Length) &&
          	(index < Count) &&
          	(index >= 0) )
              {
                  counter++;
          
          	for(int i = Count - 1; i > index; i--)
          	    RentalProperties[i] = RentalProperties[i - 1];
          	RentalProperties[index] = value;
              }
          }
          
          // This method is used to find out whether the item
          // passed as argument exists in the collection
          bool CProperties::Contains(Object ^ value)
          {
              bool found = false;
          
              for(int i = 0; i < Count; i++)
          	if( dynamic_cast<CRentalProperty ^>(
          	    this[i])->Equals(dynamic_cast<CRentalProperty ^>(value)) )
          		found = true;
          
              return found;
          }
          
          // This method is used to check whether the item passed as 
          // argument exists in the collection. If so, it returns its index
          int CProperties::IndexOf(Object ^ value)
          {
              int custIndex = -1;
          
              for(int i = 0; i < Count; i++)
              {
          	if( dynamic_cast<CRentalProperty ^>(
          	    this[i])->Equals(dynamic_cast<CRentalProperty ^>(value)) )
          	{
          	    custIndex = i;
          	    break;
          	}
              }
          
              return custIndex;
          }
          
          // This method is used to delete the item 
          // positioned at the index passed as argument
          void CProperties::RemoveAt(int index)
          {
              if( (index >= 0) && (index < Count) )
              {
          	for(int i = index; i < Count - 1; i++)
          	    RentalProperties[i] = RentalProperties[i + 1];
          	counter--;
              }
          }
          
          // This method first checks the existence of
          // the item passed as argument. If the item exists, 
          // the method deletes it
          void CProperties::Remove(Object ^ value)
          {
              RemoveAt(IndexOf(value));
          }
          
          // This methods deletes all items from the collection
          void CProperties::Clear(void)
          {
              counter = 0;
          }
          
          // This method is used to get the property positioned
          // at the index passed as argument
          CRentalProperty ^ CProperties::Get(int index)
          {
          	return dynamic_cast<CRentalProperty ^>(RentalProperties[index]);
          }
          
        3. Access the Exercise.cpp source file and change it as follows:
          #include "RentalProperty.h"
          #include "Properties.h"
          
          using namespace System;
          
          int main()
          {
              CProperties ^ properties = gcnew CProperties;
              CRentalProperty ^ rental = nullptr;
          
              rental = gcnew CRentalProperty;
              rental->PropertyCode = 737495;
              rental->PropertyType = PropertyTypes::Apartment;
              rental->PropertyCondition = PropertyConditions::Good;
              rental->Bedrooms = 1;
              rental->Bathrooms = 1;
              rental->MonthlyRent = 950.00;
              properties->Add(rental);
          
              rental = gcnew CRentalProperty;
              rental->PropertyCode = 293749;
              rental->PropertyType = PropertyTypes::SingleFamily;
              rental->PropertyCondition = PropertyConditions::Excellent;
              rental->Bedrooms = 5;
              rental->Bathrooms = 3.5;
              rental->MonthlyRent = 2550.75;
              properties->Add(rental);
          
              rental = gcnew CRentalProperty;
              rental->PropertyCode = 224006;
              rental->PropertyType = PropertyTypes::Apartment;
              rental->PropertyCondition = PropertyConditions::Excellent;
              rental->Bedrooms = 2;
              rental->Bathrooms = 1;
              rental->MonthlyRent = 1250.55;
              properties->Add(rental);
          
              rental = gcnew CRentalProperty;
              rental->PropertyCode = 197249;
              rental->PropertyType = PropertyTypes::Townhouse;
              rental->PropertyCondition = PropertyConditions::BadShape;
              rental->Bedrooms = 4;
              rental->Bathrooms = 2.5;
              rental->MonthlyRent = 1750.65;
              properties->Add(rental);
          	
              rental = gcnew CRentalProperty;
              rental->PropertyCode = 592795;
              rental->PropertyType = PropertyTypes::SingleFamily;
          	rental->PropertyCondition = PropertyConditions::Good;
              rental->Bedrooms = 3;
              rental->Bathrooms = 2.00;
              rental->MonthlyRent = 1870.35;
              properties->Add(rental);
          
              int i = 1;
              Console::WriteLine(L"<+> Solas Properties Rental <+>");
              Console::WriteLine(L"<->   Properties Listing    <->");
              for each(CRentalProperty ^ prop in properties)
              {
          	Console::WriteLine(L"-------------------------------");
          	Console::WriteLine(L"{0}. Property Details", i.ToString());
          	Console::WriteLine(L"Property #:    {0}",
          			prop->PropertyCode);
          	Console::WriteLine(L"Property Type: {0}",
          			prop->PropertyType);
          	Console::WriteLine(L"Condition:     {0}",
          			prop->PropertyCondition);
          	Console::WriteLine(L"Bedrooms:      {0}",
          			prop->Bedrooms);
          	Console::WriteLine(L"Bathrooms:     {0}",
          			prop->Bathrooms);
          	Console::WriteLine(L"Monthly Rent:  {0}",
          			prop->MonthlyRent);
          	i++;
              }
              Console::WriteLine(L"================================");
          
              CRentalProperty ^ item1 = gcnew CRentalProperty;
              item1->PropertyCode = 293749;
              item1->PropertyType = PropertyTypes::SingleFamily;
              item1->PropertyCondition = PropertyConditions::Excellent;
              item1->Bedrooms = 5;
              item1->Bathrooms = 3.5;
              item1->MonthlyRent = 2550.75;
          
              Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
              Console::WriteLine(L"-=- Sample Property -=-");
              Console::WriteLine(L"Property #:    {0}",
          			item1->PropertyCode);
              Console::WriteLine(L"Property Type: {0}",
          			item1->PropertyType);
              Console::WriteLine(L"Condition:     {0}",
          			item1->PropertyCondition);
              Console::WriteLine(L"Bedrooms:      {0}",
          			item1->Bedrooms);
              Console::WriteLine(L"Bathrooms:     {0}",
          			item1->Bathrooms);
              Console::WriteLine(L"Monthly Rent:  {0}",
          			item1->MonthlyRent);
          
              Console::WriteLine(L"-------------------------------------------");
              if( properties->Contains(item1) == true )
                  Console::WriteLine("That property already exists in the listing");
              else
                  Console::WriteLine("The property was not found in our database");
          
              Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
          
              CRentalProperty ^ item2 = gcnew CRentalProperty;
              item2->PropertyCode = 290004;
              item2->PropertyType = PropertyTypes::SingleFamily;
              item2->PropertyCondition = PropertyConditions::Excellent;
              item2->Bedrooms = 5;
              item2->Bathrooms = 3.5;
              item1->MonthlyRent = 2550.75;
          
              Console::WriteLine(L"-=- Sample Property -=-");
              Console::WriteLine(L"Property #:    {0}",
          			item2->PropertyCode);
              Console::WriteLine(L"Property Type: {0}",
          			item2->PropertyType);
              Console::WriteLine(L"Condition:     {0}",
          			item2->PropertyCondition);
              Console::WriteLine(L"Bedrooms:      {0}",
          			item2->Bedrooms);
              Console::WriteLine(L"Bathrooms:     {0}",
          			item2->Bathrooms);
              Console::WriteLine(L"Monthly Rent:  {0}",
          			item2->MonthlyRent);
          
              Console::WriteLine(L"-------------------------------------------");
              if( properties->Contains(item2) == true )
                  Console::WriteLine("That property already exists in the listing");
              else
                  Console::WriteLine("The property was not found in our database");
              Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
          
              CRentalProperty ^ item3 = gcnew CRentalProperty;
              item3->PropertyCode = 224006;
              item3->PropertyType = PropertyTypes::Apartment;
              item3->PropertyCondition = PropertyConditions::Excellent;
              item3->Bedrooms = 2;
              item3->Bathrooms = 1;
              item3->MonthlyRent = 1250.55;
          
              Console::WriteLine(L"-=- Sample Property -=-");
              Console::WriteLine(L"Property #:    {0}",
          			item3->PropertyCode);
              Console::WriteLine(L"Property Type: {0}",
          			item3->PropertyType);
              Console::WriteLine(L"Condition:     {0}",
          			item3->PropertyCondition);
              Console::WriteLine(L"Bedrooms:      {0}",
          			item3->Bedrooms);
              Console::WriteLine(L"Bathrooms:     {0}",
          			item3->Bathrooms);
              Console::WriteLine(L"Monthly Rent:  {0}",
          			item3->MonthlyRent);
          	Console::WriteLine(L"The index of this property is: {0}",
          		properties->IndexOf(item3));
              Console::WriteLine(L"8--8--8--8--8--8--8--8--8--8--8--8--8--8--8");
          	
              properties->RemoveAt(2);
              
              Console::WriteLine(L"After removing the 3rd item");
              Console::WriteLine(L"-------------------------------");
              Console::WriteLine(L"<+> Solas Properties Rental <+>");
              Console::WriteLine(L"<->   Properties Listing    <->");
              
              for(int n = 0; n < properties->Count; n++)
              {
          	CRentalProperty ^ prop =
          		dynamic_cast<CRentalProperty ^>(properties[n]);
          	Console::WriteLine(L"-------------------------------");
          	Console::WriteLine(L"{0}. Property Details", (n+1).ToString());
          	Console::WriteLine(L"Property #:    {0}",
          			prop->PropertyCode);
          	Console::WriteLine(L"Property Type: {0}",
          			prop->PropertyType);
          	Console::WriteLine(L"Condition:     {0}",
          			prop->PropertyCondition);
          	Console::WriteLine(L"Bedrooms:      {0}",
          			prop->Bedrooms);
          	Console::WriteLine(L"Bathrooms:     {0}",
          			prop->Bathrooms);
          	Console::WriteLine(L"Monthly Rent:  {0}",
          			prop->MonthlyRent);
              }
              Console::WriteLine(L"================================");
          	
              CRentalProperty ^ item4 = gcnew CRentalProperty;
              item4->PropertyCode = 293749;
              item4->PropertyType = PropertyTypes::SingleFamily;
              item4->PropertyCondition = PropertyConditions::Excellent;
              item4->Bedrooms = 5;
              item4->Bathrooms = 3.5;
              item4->MonthlyRent = 2550.75;
              properties->Remove(item4);
              
              Console::WriteLine(L"After removing another item");
              Console::WriteLine(L"-------------------------------");
              Console::WriteLine(L"<+> Solas Properties Rental <+>");
              Console::WriteLine(L"<->   Properties Listing    <->");
              
              for(int n = 0; n < properties->Count; n++)
              {
          	CRentalProperty ^ prop = 
          		dynamic_cast<CRentalProperty ^>(properties[n]);
          	Console::WriteLine(L"-------------------------------");
          	Console::WriteLine(L"{0}. Property Details", (n+1).ToString());
          	Console::WriteLine(L"Property #:    {0}",
          			prop->PropertyCode);
          	Console::WriteLine(L"Property Type: {0}",
          			prop->PropertyType);
          	Console::WriteLine(L"Condition:     {0}",
          			prop->PropertyCondition);
          	Console::WriteLine(L"Bedrooms:      {0}",
          			prop->Bedrooms);
          	Console::WriteLine(L"Bathrooms:     {0}",
          			prop->Bathrooms);
          	Console::WriteLine(L"Monthly Rent:  {0}",
          			prop->MonthlyRent);
              }
              Console::WriteLine(L"================================");
              
              properties->Clear();
              Console::WriteLine(L"After removing all items");
              Console::WriteLine(L"<+> Solas Properties Rental <+>");
              Console::WriteLine(L"<->   Properties Listing    <->");
              
              for(int n = 0; n < properties->Count; n++)
              {
          	CRentalProperty ^ prop = 
          		dynamic_cast<CRentalProperty ^>(properties[n]);
          	Console::WriteLine(L"-------------------------------");
          	Console::WriteLine(L"{0}. Property Details", (n+1).ToString());
          	Console::WriteLine(L"Property #:    {0}",
          			prop->PropertyCode);
          	Console::WriteLine(L"Property Type: {0}",
          			prop->PropertyType);
          	Console::WriteLine(L"Condition:     {0}",
          			prop->PropertyCondition);
          	Console::WriteLine(L"Bedrooms:      {0}",
          			prop->Bedrooms);
          	Console::WriteLine(L"Bathrooms:     {0}",
          			prop->Bathrooms);
          	Console::WriteLine(L"Monthly Rent:  {0}",
          			prop->MonthlyRent);
              }
              Console::WriteLine(L"================================");
              return 0;
          }
        4. Execute the application to see the result:
          <+> Solas Properties Rental <+>
          <->   Properties Listing    <->
          -------------------------------
          1. Property Details
          Property #:    737495
          Property Type: Apartment
          Condition:     Good
          Bedrooms:      1
          Bathrooms:     1
          Monthly Rent:  950
          -------------------------------
          2. Property Details
          Property #:    293749
          Property Type: SingleFamily
          Condition:     Excellent
          Bedrooms:      5
          Bathrooms:     3.5
          Monthly Rent:  2550.75
          -------------------------------
          3. Property Details
          Property #:    224006
          Property Type: Apartment
          Condition:     Excellent
          Bedrooms:      2
          Bathrooms:     1
          Monthly Rent:  1250.55
          -------------------------------
          4. Property Details
          Property #:    197249
          Property Type: Townhouse
          Condition:     BadShape
          Bedrooms:      4
          Bathrooms:     2.5
          Monthly Rent:  1750.65
          -------------------------------
          5. Property Details
          Property #:    592795
          Property Type: SingleFamily
          Condition:     Good
          Bedrooms:      3
          Bathrooms:     2
          Monthly Rent:  1870.35
          ================================
          8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
          -=- Sample Property -=-
          Property #:    293749
          Property Type: SingleFamily
          Condition:     Excellent
          Bedrooms:      5
          Bathrooms:     3.5
          Monthly Rent:  2550.75
          -------------------------------------------
          That property already exists in the listing
          8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
          -=- Sample Property -=-
          Property #:    290004
          Property Type: SingleFamily
          Condition:     Excellent
          Bedrooms:      5
          Bathrooms:     3.5
          Monthly Rent:  0
          -------------------------------------------
          The property was not found in our database
          8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
          -=- Sample Property -=-
          Property #:    224006
          Property Type: Apartment
          Condition:     Excellent
          Bedrooms:      2
          Bathrooms:     1
          Monthly Rent:  1250.55
          The index of this property is: 2
          8--8--8--8--8--8--8--8--8--8--8--8--8--8--8
          After removing the 3rd item
          -------------------------------
          <+> Solas Properties Rental <+>
          <->   Properties Listing    <->
          -------------------------------
          1. Property Details
          Property #:    737495
          Property Type: Apartment
          Condition:     Good
          Bedrooms:      1
          Bathrooms:     1
          Monthly Rent:  950
          -------------------------------
          2. Property Details
          Property #:    293749
          Property Type: SingleFamily
          Condition:     Excellent
          Bedrooms:      5
          Bathrooms:     3.5
          Monthly Rent:  2550.75
          -------------------------------
          3. Property Details
          Property #:    197249
          Property Type: Townhouse
          Condition:     BadShape
          Bedrooms:      4
          Bathrooms:     2.5
          Monthly Rent:  1750.65
          -------------------------------
          4. Property Details
          Property #:    592795
          Property Type: SingleFamily
          Condition:     Good
          Bedrooms:      3
          Bathrooms:     2
          Monthly Rent:  1870.35
          ================================
          After removing another item
          -------------------------------
          <+> Solas Properties Rental <+>
          <->   Properties Listing    <->
          -------------------------------
          1. Property Details
          Property #:    737495
          Property Type: Apartment
          Condition:     Good
          Bedrooms:      1
          Bathrooms:     1
          Monthly Rent:  950
          -------------------------------
          2. Property Details
          Property #:    197249
          Property Type: Townhouse
          Condition:     BadShape
          Bedrooms:      4
          Bathrooms:     2.5
          Monthly Rent:  1750.65
          -------------------------------
          3. Property Details
          Property #:    592795
          Property Type: SingleFamily
          Condition:     Good
          Bedrooms:      3
          Bathrooms:     2
          Monthly Rent:  1870.35
          ================================
          After removing all items
          <+> Solas Properties Rental <+>
          <->   Properties Listing    <->
          ================================
          Press any key to continue . . .
        5. Close the DOS window and return to your programming environment

        Previous Copyright © 2007-2025, FunctionX Monday 14 October 2024, 10:12 Home