Pro Visual C++-CLI And The .NET 2.0 Platform (2006) [eng]-1
.pdf238C H A P T E R 6 ■ I N T E G R A T E D X M L D O C U M E N T A T I O N
///</code>
///</example>
void exampleTag() {}
///<exception cref="System::OverflowException">
///This method might throw this exception (NOT)
///</exception>
void exceptionTag() {}
///<permission cref="System::Security::PermissionSet">
///Go ahead anyone can access me.
///</permission>
void permissionTag() {}
///<summary>
///Some <c>Program code</c> in a summary
///</summary>
void cTag() {}
///<example>
///Some code in an example tag
///<code>
///A code statement;
///Another code statement;
///</code>
///</example> void codeTag() {}
///<summary>
///<para>This is the first paragraph which spans more than one line
///When the document window is small enough.</para><para>This is the
///next paragraph which started in a new line.</para>
///</summary>
void paraTag() {}
///<summary>
///A bullet list
///<list type="bullet">
///<item> bullet </item>
///<item> bullet </item>
///</list>
///A numbered list
///<list type="number">
///<item> entry 1 </item>
///<item> entry 2 </item>
///<item> entry n </item>
///</list>
///A table
///<list type="table">
///<item>
///<description>row 1 -- column a</description>
///<description>row 1 -- column b</description>
///<description>row 1 -- column c</description>
///</item>
C H A P T E R 6 ■ I N T E G R A T E D X M L D O C U M E N T A T I O N |
239 |
///<item>
///<description>row 2 -- column a</description>
///<description>row 2 -- column b</description>
///<description>row 2 -- column c</description>
///</item>
///</list>
///A definition of terms
///<list type="table">
///<listheader>
///<term>Properties</term>
///<description>Initial Value</description>
///</listheader>
///<item>
///<term>term1 name</term>
///<description>term1 description</description>
///</item>
///<item>
///<term>term2 name</term>
///<description>term2 description</description>
///</item>
///<item>
///<term>termN name</term>
///<description>termN description</description>
///</item>
///</list>
///</summary>
void listTag() {}
///<summary> This is a summary with an <include> tag containing
///a <list type="bullet">
///<include file='document.xml' path='AllDoc/Entry[@num="1"]/*' />
///</summary>
///<include file='document.xml' path='AllDoc/Entry[@num="2"]/*' /> void includeTag() {}
///<summary> This summary references the <paramref name="param1"/>
///parameter of the method
///</summary>
void paramrefTag(int param1) {}
///<summary>
///The basic see tag <see cref="File" />
///The enhanced see tag <see cref="FileInfo">System::IO:FileInfo</see>
///</summary>
void seeTag() {}
///<summary>
///The basic see tag [<seealso cref="File" />] Nothing here
///The enhanced see tag <seealso cref="FileInfo">FileInfo</seealso>
///</summary>
void seealsoTag() {}
};
}
240 C H A P T E R 6 ■ I N T E G R A T E D X M L D O C U M E N T A T I O N
Summary
This chapter described in detail the integrated XML documentation provided by the C++/CLI compiler, beginning with the basics of documentation and the triple slash comment provided by the compiler, followed by each of the standard tags available to the C++/CLI developer. The chapter ended with an examination of the triple slash comment in action in an example that featured every common documentation tag.
In the next chapter, you’ll begin exploring the .NET development and, in particular, the collection functionality provided by the .NET Framework class library.
C H A P T E R 7
■ ■ ■
Collections
Anyone who has been around the coding world for any length of time has more than likely written his or her own collection routine—probably a simply linked list. Newer programmers may not have written one of their own, but instead, in the case of C++ programmers, used the Standard Template Library (STL) version of a linked list. Either way, most programmers have found a need to work with collections. The .NET Framework uses collections as well. Because collections are so common, the
.NET Framework class library provides a large number of different types.
There are, in fact, three primary sets of collections available to the .NET Framework programmer:
System::Collections, System::Collections::Specialized, and System::Collections::Generic. As the names of these namespaces suggest, the first set contains standard collection types, the second contains collection types with a more specific purpose, and the third set contains collections specifically targeting the new generic type introduced in the .NET Framework version 2.0.
Something to be aware of is that the names of the three namespaces just mentioned seem to imply that the specialized collections and generic collections are inherited from the standard collections, but in fact there is no such relationship. The namespaces are just groupings of different types of collections.
This chapter focuses on the standard collection set shown in Table 7-1 and the generic collection set shown in Table 7-2. However, the .NET Framework class library has many other specific collections scattered throughout the many namespaces—for example,
System::Text::RegularExpressions::Group, System::Security::PermissionSet, System::Web::UI::WebControls::DataKeyCollection, and even System::Array.
Table 7-1. .NET Standard Collection Classes
Collection |
Description |
ArrayList |
An array that grows dynamically |
BitArray |
An array of bit values (either 1 or 0) |
BitVector32 |
A small collection that will represent Boolean or small integers |
|
within 32 bits of memory |
CollectionBase |
An abstract base class for deriving strongly typed collections |
DictionaryBase |
An abstract base class for deriving strongly typed collections of |
|
key/value pairs |
Hashtable |
A collection of key/value pairs organized based on a hash code of |
|
the key |
HybridDictionary |
A collection that switches from a ListDictionary when small to a |
|
Hashtable when large |
241
242 C H A P T E R 7 ■ C O L L E C T I O N S
Table 7-1. .NET Standard Collection Classes (Continued)
Collection |
Description |
ListDictionary |
A singular linked list recommended for lists of ten objects or less |
NameValueCollection |
A collection string of key/value pairs organized on the string key and |
|
accessible by either string key or index |
Queue |
A collection of first-in-first-out objects |
SortedList |
A collection of key/value pairs sorted by key and accessible by either |
|
key or index value |
Stack |
A collection of first-in-last-out objects |
StringCollection |
A collection of strings |
StringDictionary |
A Hashtable with the key strong typed to be a string |
|
|
Table 7-2. .NET Generic Collection Classes |
|
|
|
Collection |
Description |
|
|
Collection<T> |
A base class for generic collections from which users are urged to |
|
derive their own specialized container classes. |
Dictionary<K,V> |
A collection of key/value paired generic objects that are organized |
|
based on the key and retrieved as a KeyValuePair<K,V> struct. |
KeyedCollection<K,V> |
A base class for generic collections using key/value pairs from which |
|
users are urged to derive their own specialized container classes. |
LinkedList<T> |
A doubly (forward and backward) linked list generic object. |
List<T> |
An array of generic objects that grows dynamically. |
Queue<T> |
A collection of first-in-first-out generic objects. |
ReadOnlyCollection<T> |
A base class for a generic read-only collection from which users are |
|
urged to derive their own specialized container classes. A collection |
|
that is read-only is simply a collection with a wrapper that prevents |
|
modifying the collection. |
SortedDictionary<K,V> |
A collection of key/value paired generic objects that are sorted |
|
based on the key. |
Stack<T> |
A collection of first-in-last-out generic objects. |
|
|
To make things easier for the developer, the .NET Framework class library provides several interfaces (see Table 7-3 for standard and Table 7-4 for generic) that help provide some commonality between the collections. Learning collections is simplified because many of the collections share these interfaces, and once you learn an interface in one collection, it requires little effort to learn it in a second one.
C H A P T E R 7 ■ C O L L E C T I O N S |
243 |
Table 7-3. .NET Standard Collection Interfaces
Interface |
Description |
ICollection |
Defines methods to determine the size, and provide synchronization |
|
and enumeration through all nongeneric collections |
IComparer |
Exposes a method to compare objects of the collection |
IDictionary |
Defines methods to allow access to key/value pairs within the |
|
collection |
IDictionaryEnumerator |
Exposes methods to access keys and values while enumerating |
|
a collection |
IEnumerable |
Exposes a method to retrieve an object that implements the |
|
IEnumerator interface |
IEnumerator |
Exposes a method to enumerate through a collection |
IHashCodeProvider |
Exposes a method to provide a custom hash algorithm |
IList |
Defines methods to add, insert, delete, and access objects using an |
|
index |
|
|
■Note Default implementations of collections in System::Collections::Generic are not synchronized (thread-safe).
Table 7-4. .NET Generic Collection Interfaces
Interface |
Description |
ICollection<T> |
Defines properties to determine the size of the collection and methods to |
|
add, remove, copy, and clear elements, as well as check for the existence |
|
of elements |
IComparer<T> |
Exposes a method to compare objects of the collection |
IDictionary<K,V> |
Defines properties to allow access to key/value pairs within the collection and |
|
methods to add and remove elements, as well as check for the existence of |
|
elements |
IEnumerable<T> |
Exposes a method to retrieve an object that implements the IEnumerator<T> |
|
interface |
IEnumerator<T> |
Exposes a method to enumerate through a collection |
IList<T> |
Defines methods to add, insert, delete, and access objects using an index |
|
|
IEnumerable, IEnumerator, and for each
Even though each of the collections in Tables 7-1 and 7-2 is implemented differently internally, all except BitVector32 implement either the IEnumerable or IEnumerable<T> interface. These interfaces expose one member method, GetEnumerator(). This method returns a handle to an object that
244 |
C H A P T E R 7 ■ C O L L E C T I O N S |
implements either the IEnumerator or IEnumerator<T> interface. And both the IEnumerator and IEnumerator<T> interfaces expose member methods that allow all collections to be handled the exact same way if there is a need.
The IEnumerator and IEnumerator<T> interfaces are fairly simple. You call the method MoveNext() to advance the enumerator to the next item in the collection, and then you grab the item out of the Current property. You know you have reached the end of the collection when MoveNext() returns false.
The IEnumerator interface contains one more method called Reset(), which the implementing class should define, that moves the enumerator back to the start of the collection.
Sound simple enough? There is an even easier way to iterate through a collection. Remember the for each statement? It implements all this IEnumerator and IEnumerator<T> stuff for you.
The following code shows equivalent implementation, first using the IEnumerable and IEnumerator interfaces, and then for each. Both are implemented on the same array (which also implements the IEnumerable interface even though it is not a member of System::Collections):
using namespace System;
using namespace System::Collections;
void main()
{
array<int>^ IntList = gcnew array<int> { 1, 2, 3, 4, 5 };
IEnumerable ^collection = (IEnumerable^)IntList; //Not really needed
IEnumerator ^enumerator = collection->GetEnumerator();
Console::WriteLine("IEnumerator\n----------- |
"); |
while (enumerator->MoveNext())
{
int i = (int)enumerator->Current; Console::WriteLine(i);
}
Console::WriteLine("\nfor each\n-------- |
"); |
for each (int i in IntList) Console::WriteLine(i);
}
Figure 7-1 shows the results of the IEnum_foreach.exe program.
The choice of which to use is entirely up to you. There are a few occasions when your only choice is to use IEnumerable/IEnumerator. I show an example in HashSortList.cpp later in the chapter. I find for each to be easier to use, and I try to use it whenever possible.
C H A P T E R 7 ■ C O L L E C T I O N S |
245 |
Figure 7-1. Results of IEnum_foreach.exe
Standard Collections
Now that you’ve looked at the major similarity among the .NET Framework class library collections, you’ll take a look at how they differ. You’ll start with the standard, or more common, collections of the class library. There’s nothing new about these collection types, as they’ve been around for quite a long time. What’s different is how the .NET Framework class library implements them and what interfaces the library provides.
ArrayList
If you’ve never coded an array, then you probably haven’t been coding very long. Arrays, with their simple syntax, are the easiest of all collections to work with, especially when you know exactly how much data you’re working with. Unfortunately, they quickly lose their usefulness when the number of data elements is unknown.
The ArrayList is a solution to the shortcomings of the simple array. You get the simple syntax of an array without having to worry about the number of data elements. Well, that’s not quite accurate: you actually get a slightly more complex array syntax, but only after the array is already loaded.
Loading the ArrayList requires member method calls—simple ones, but method calls just the same. Once the ArrayList is loaded, though, you can treat it almost exactly as you would a simple array.
There is nothing difficult about creating an ArrayList; it is simply a standard class. It does have three different constructors. The default takes no parameters. This constructor creates an ArrayList with a starting Capacity of 16:
ArrayList ^alist = gcnew ArrayList();
That doesn’t mean that the ArrayList is restricted to 16; it just means that the first internal array contains space for 16 elements. If the number of elements, also known as the Count, exceeds the Capacity, then the Capacity is doubled or, in other words, the internal array of the ArrayList doubles and the original array is copied to the new, expanded array.
■ C O L L E C T I O N S
When the size of the ArrayList exceeds its capacity, the capacity is doubled. This could cause the ArrayList to be larger than is useful. For example, if your capacity is 20,000 and you add a 20,001st element, then the capacity becomes 40,000, which might not be what you want.
The second constructor allows you to set the initial Capacity. This allows you to optimize the loading of the ArrayList, as no doubling of the Capacity need occur if you can restrict the size of the
ArrayList to less than the Capacity.
ArrayList ^alist = gcnew ArrayList(300);
The last constructor allows you to create an ArrayList from another specified collection. This constructor copies the elements from the originating collection and then sets the Capacity and Count to the number of elements copied.
ArrayList ^org = gcnew ArrayList(); //...populate org
ArrayList ^alist = gcnew ArrayList(org);
It is possible to get the Count or Capacity.
int count = alist->Count;
int capacity = alist->Capacity;
It is also possible to change the Capacity of an ArrayList at runtime by changing the Capacity property. If you change the Capacity to 0, the Capacity changes to the default Capacity of 16. Here is how you would code the setting of the capacity to 123:
alist->Capacity = 123;
■Caution Setting the Capacity to a value less than the Count of the ArrayList will result in an
ArgumentOutOfRangeException being thrown.
Loading an ArrayList requires the use of member methods. All of the member methods are quite simple to use and self-explanatory. You can append or insert one or a range of elements to an ArrayList. You can also remove a specific element either by index or by specific content, or you can remove a range of elements by index.
alist->Add("One");
array<String^>^ morenums1 = gcnew array<String^> {"Three", "Six"}; alist->AddRange(morenums1);
alist->Insert(1, "Two");
array<String^>^ morenums2 = gcnew array<String^> {"Four", "Five"}; alist->InsertRange(3, morenums2);
alist->Remove("Six"); alist->RemoveAt(1); alist->RemoveRange(0,4); // Index, Count
Once the ArrayList is loaded, it is possible to access the ArrayList in nearly the same way as a simple array. The only difference is that you are accessing a default index property into the ArrayList, instead of accessing the array element directly.
C H A P T E R 7 ■ C O L L E C T I O N S |
247 |
alist[1] = "Three";
for (int i = 0; i < alist->Count; i++)
{
Console::Write("{0} ", alist[i]);
}
■Caution Trying to access an ArrayList element that does not exist via the default index property will throw an ArgumentOutOfRangeException.
■Note The default index property index starts at 0, just like any other array in C++.
The ArrayList provides a few useful methods that might make your coding life a little easier. For example, it is possible to reverse the order of all the elements of the ArrayList with Reverse().
alist->Reverse();
Another useful method is the Sort() method, which allows you to sort the ListArray.
Alist->Sort();
It is also possible to do a binary search of a sorted ArrayList to search for a specific element. With this method, the element’s index is returned. If the element is not found, then the search method returns a negative number that indicates the index of the next largest object in the ArrayList.
int indx = alist->BinarySearch("Four");
Similar to the binary search, you can do a linear search to check if the ArrayList contains an element. If the search finds the element, it returns true. If not, it returns false.
bool fnd = alist->Contains("One");
Listing 7-1 shows the ArrayList in action and demonstrates many of the functionalities described previously.
Listing 7-1. Working with ArrayLists
using namespace System;
using namespace System::Collections;
void main()
{
ArrayList ^alist = gcnew ArrayList(4); // will double to 8 alist->Add("One");
alist->Add("-"); alist[1] = "Three";
alist->Insert(1, "Two");
array<String^>^ morenums = gcnew array<String^> {"Four", "Five"};
alist->AddRange(morenums);