C# Generics Recipes—Replacing the ArrayList with Its Generic Counterpart
Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio
| CSharp-Online.NET:Articles |
| C# Articles |
| © 2006 O'Reilly Media, Inc. |
Contents |
4.4 Replacing the ArrayList with Its Generic Counterpart
Problem
You want to enhance the performance of your application as well as make the code easier to work with by replacing all ArrayList objects with the generic version. This is imperative when you find that structures or other value types are being stored in these data structures, resulting in boxing/unboxing operations.
Solution
Replace all occurrences of the System.Collection.ArrayList class with the more efficient
generic System.Collections.Generic.List class.
Here is a simple example of using a System.Collections.ArrayList object:
public static void UseNonGenericArrayList( ) { // Create and populate an ArrayList. ArrayList numbers = new ArrayList( ); numbers.Add(1); // Causes a boxing operation to occur numbers.Add(2); // Causes a boxing operation to occur // Display all integers in the ArrayList. // Causes an unboxing operation to occur on each iteration foreach (int i in numbers) { Console.WriteLine(i); } numbers.Clear( ); }
Here is that same code using a System.Collections.Generic.List object:
public static void UseGenericList( ) { // Create and populate a List. List<int> numbers = new List<int>( ); numbers.Add(1); numbers.Add(2); // Display all integers in the ArrayList. foreach (int i in numbers) { Console.WriteLine(i); } numbers.Clear( ); }
Discussion
Since ArrayLists are used in almost all applications, it is a good place to start to enhance the performance of your application. For simple implementations of the ArrayList in your application, this substitution should be quite easy. However, there
are some things to watch out for. For example, the generic List class does not implement the ICloneable interface while the ArrayList class does.
Table 4-1 shows the equivalent members that are implemented in both classes.
Table 4-1. Equivalent members in the ArrayList and the generic List classes
| Members in the ArrayList class | Equivalent members in the generic List class |
Capacity property
| Capacity property
|
Count property
| Count property
|
IsFixedSize property
| ((IList)myList).IsFixedSize
|
IsReadOnly property
| ((IList)myList).IsReadOnly
|
IsSynchronized property
| ((IList)myList).IsSynchronized
|
Item property
| Item property
|
SyncRoot property
| ((IList)myList).SyncRoot
|
Adapter static method
| N/A |
Add method
| Add method
|
AddRange method
| AddRange method
|
| N/A | AsReadOnly method
|
BinarySearch method
| BinarySearch method
|
Clear method
| Clear method
|
Clone method
| GetRange(0, numbers.Count)
|
Contains method
| Contains method
|
| N/A | ConvertAll method
|
CopyTo method
| CopyTo method
|
| N/A | Exists method
|
| N/A | Find method
|
| N/A | FindAll method
|
| N/A | FindIndex method
|
| N/A | FindLast method
|
| N/A | FindLastIndex method
|
| N/A | ForEach method
|
FixedSize static method
| N/A |
GetRange method
| GetRange method
|
IndexOf method
| IndexOf method
|
Insert method
| Insert method
|
InsertRange method
| InsertRange method
|
LastIndexOf method
| LastIndexOf method
|
ReadOnly static method
| AsReadOnly method
|
Remove method
| Remove method
|
| N/A | RemoveAll method
|
RemoveAt method
| RemoveAt method
|
RemoveRange method
| RemoveRange method
|
Repeat static method
| Use a for loop and the Add method
|
Reverse method
| Reverse method
|
SetRange method
| InsertRange method
|
Sort method
| Sort method
|
Synchronized static method
| lock(myList.SyncRoot) {…}
|
ToArray method
| ToArray method
|
| N/A | TrimExcess method
|
TrimToSize method
| TrimToSize method
|
| N/A | TrueForAll method
|
In several cases within Table 4-1 there is not a one-to-one correlation between the members of an ArrayList and the members of the generic List class. Starting with the properties, notice that only the Capacity, Count, and Item properties are present in both classes. To make up for the missing properties in the List class, you can perform a cast to an IList. The following code shows how to use these casts to get at the missing properties.
List<int> numbers = new List<int>( ); Console.WriteLine(((IList)numbers).IsReadOnly); Console.WriteLine(((IList)numbers).IsFixedSize); Console.WriteLine(((IList)numbers).IsSynchronized); Console.WriteLine(((IList)numbers).SyncRoot);
Note that due to the absence of code that returns a synchronized version of a generic List and the absence of code that returns a fixed size generic List, the IsFixedSize
and IsSynchronized properties will always return false. The SyncRoot property will
always return the same object on which it is called. Essentially, this property returns
the this pointer. Microsoft has decided to remove the ability to create a synchronous
wrapper from any of the generic collection classes. Instead, they recommend
using the lock keyword to lock the entire collection or another type of synchronization
object that suits your needs.
The ArrayList has several static methods to which there is no direct equivalent
method in the generic List class. To fix this you have to do a little work. The closest
match for the static ArrayList.ReadOnly method is the AsReadOnly instance method of
the generic List class. This makes for a fairly simple substitution.
The static ArrayList.Repeat method has no direct equivalent in the generic List class. So instead, you can use the following generic method:
public static void Repeat<T>(List<T> list, T obj, int count) { if (count < 0) { throw (new ArgumentException( "The count parameter must be greater or equal to zero.")); } for (int index = 0; index < count; index++) { list.Add(obj); } }
This generic method takes three parameters:
list
The generic List object
obj
The object that will be added to the generic List object a specified number of times
count
The number of times to add the object contained inobjto the genericListobject
Since the Clone method is also missing from the generic List class (due to the fact
that this class does not implement the ICloneable interface), you can instead use the
GetRange method of the generic List class.
List<int> oldList = new List<int>( ); // Populate oldList... List<int> newList = oldList.GetRange(0, oldList.Count);
The GetRange method performs a shallow copy (similar to the Clone method of the
ArrayList) of a range of elements in the List object. In this case the range of elements
includes all elements.
TheArrayListhas a default initial capacity of 16 elements, while theList<T>has a default initial capacity of only 4 elements. This means that theList<T>will have to be resized (and reallocated) 3 times by the time the 17th element is added, whereas theArrayListwill have to be resized only one time. This should be taken into account when evaluating the performance of your application.
See Also
See the "System.Collections.ArrayList Class" and "System.Collections.Generic.List Class" topics in the MSDN documentation.
|

