Built-In Collection Interfaces
Overview of .NET Collection Interfaces
|
|
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
- IComparer: If you derive a class from this interface, you can
define how two objects would be compared for similarity or difference
- IDictionary: This interface is used to create a collection class
where each item is made of a key=value combination
The ICollection Interface
|
|
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
{
};
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;
}
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: Starting a Custom Collection Class |
|
- Start Microsoft Visual C++ and create a new CLR Empty Project named SolasPropertyRental1
- To create a new class, in the Solution Explorer, right-click Solas Property Rental1
->
Add -> Class...
- In the Templates list, click C++ Class and click Add
- Set the Name to CRentalProperty and press Enter
- 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);
};
- 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;
}
- To create a new file, in the Solution Explorer, right-click Solas Property Rental1
->
Add -> New Item...
- In the Templates list, click C++ File (.cpp)
- Set the Name to Exercise and press Enter
- Change the file as follows:
using namespace System;
int main()
{
return 0;
}
- Save all
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: Implementing the IList Interface |
|
- To create a new class, in the Class View, right-click Solas Property Rental1
->
Add -> Class...
- In the Templates list, click C++ Class and click Add
- Set the Name to CProperties and press Enter
- 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);
};
|
- 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;
}
|
- Save all
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: Implementing the IsFixedSize Property |
|
- Access 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 bool IsFixedSize
{
bool get() { return false; }
}
virtual void CopyTo(Array ^, int);
virtual IEnumerator ^ GetEnumerator(void);
};
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: Implementing the IsReadOnly Property |
|
- 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);
};
- In the Class View, right-click CProperties -> Add ->
Function...
- Accept the Return Type as int and set the Function Name to
Add
- In the Parameter Type, type Object ^
- In the Parameter Name, type value and click Add
- Click the virtual check box
- Click Finish
- In the Class View, right-click CProperties -> Add ->
Function...
- Set the Return Type to void
- Set the Function Name to insert
- In the Parameter Type, select int
- In the Parameter Name, type index and click Add
- In the Parameter Type, type Object ^
- In the Parameter Name, type value and click Add
- Click the virtual check box
- Click Finish
- 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
};
|
- In the Class View, right-click CProperties -> Add ->
Function...
- Set the Return Type to bool
- Set the Function Name to Contains
- In the Parameter Type, type Object ^
- In the Parameter Name, type value and click Add
- Click the virtual check box
- Click Finish
- In the Class View, right-click CProperties -> Add ->
Function...
- Accept the Return Type as int and set the Function Name to IndexOf
- In the Parameter Type, type Object ^
- In the Parameter Name, type value and click Add
- Click the virtual check box
- Click Finish
- In the Class View, right-click CProperties -> Add ->
Function...
- Set the Return Type to void
- Set the Function Name to RemoveAt
- In the Parameter Type, select int
- In the Parameter Name, type index and click Add
- Click the virtual check box
- Click Finish
- In the Class View, right-click CProperties -> Add ->
Function...
- Set the Return Type to void
- Set the Function Name to Remove
- In the Parameter Type, select Object ^
- In the Parameter Name, type value and click Add
- Click the virtual check box
- Click Finish
- In the Class View, right-click CProperties -> Add ->
Function...
- Set the Return Type to void
- Set the Function Name to Clear
- Click the virtual check box
- 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
|
|
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 there is still room in the collection, the item would be added to the
list
- If there is not enough room, the item would simply not be added. There
would not be a problem and the program would not crash. In fact, no
exception would be thrown if the item was not added because of lack of
space. On the other, since the compiler would not let you know that there
was a problem with "logistic", you may not know whether the item
was added or not. Therefore, if you are concerned with known whether the
item was added, you must provide this functionality yourself
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: Adding an Item to the Collection |
|
- In the Scopes combo box of the Code Editor, select CProperties and,
in the Functions combo box, select Add
- 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;
}
|
- In the Class View, right-click CProperties -> Add ->
Function...
- In the Return Type combo box, type CRentalProperty ^
- Set the Function Name to Get
- In the Parameter Type, select int
- In the Parameter Name, type index and click Add
- Click Finish
- 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]);
}
|
- 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;
}
|
- 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 . . .
|
- Close the DOS window and return to your programming environment
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:
- If the index argument holds a negative value or a value higher than
the allowed number (for example if the collection is an array) of the items
(depending on how you implement the method), the new item would not be
added, the compiler would not throw an exception, and therefore nothing
would let you know that the item was not added. If you want to find out
whether the item was formally or actually inserted or not, you must create
the functionality yourself
- If the value argument is not valid, again depending on how you
structure your class, either the item would not be inserted or something
else would go wrong. Fortunately, if the value argument is of type of
a class you created yourself, the compiler would produce an error such as
letting you know that the argument is holding a value that is conform to its
property or member variable. For example, imagine the value is a CStudent
object that has an integer member named age. If you assign a String,
such as CStudent::Age = L"Raymond", the error thrown by the
compiler would know that it is the CStudent object that is not holding a
right value and therefore this object would not even get to the collection
class
Practical
Learning: Inserting an Item in the Collection |
|
- 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
- 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;
}
}
|
- 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;
}
|
- 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 . . .
|
- 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: Identifying this Item in the Collection |
|
- Access the Properties.h header file
- In the Scopes combo box of the Code Editor, select CProperties::default
- In the Functions combo box, select get
- 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
};
- 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;
}
- Execute the application to see the result
- Close the DOS window
- Open the Properties.h header file
- 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
};
- 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
- 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;
}
- Close the DOS window
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: Checking the Existence of an Item in the Collection |
|
- 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);
};
- 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;
}
- Open the Properties.cpp source file
- 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;
}
- 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;
}
- 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 . . .
- Close the DOS window
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: Getting the Index of an Item |
|
- 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;
}
- 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;
}
- 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 . . .
- Close the DOS window
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));
}
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: Removing Some Items From the Collection |
|
- Access the Properties.cpp source file
- 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]);
}
- 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;
}
- 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 . . .
- Close the DOS window and return to your programming environment
| | | |