Non-Generic Collections in C# : Part 1
Since version 1.0, the non-generic collections have been a part of the .NET Framework. They are defined in the System.Collections
namespace. They are the general-purpose data structures and work with object references. They are therefore capable of managing any kind of object without specifying the type of object during declaration, but not in a type-safe way. This is both to their benefit and detriment. You can mix different types of data within the same collection because they work on object references. Because of this, they are helpful for managing a collection of several object kinds or when it is unknown in advance what kind of objects are being kept. However, non-generic collections lack the type-safety that is present in generic collections if you want to use them to store a certain kind of object.
The non-generic collections are defined by a set of interfaces and classes that implements those interfaces. These interfaces include ICollection
, IEnumerable
, IList
, IDictionary
, and several others. The classes that implement these interfaces include ArrayList
, Hashtable
, Queue
, Stack
, and others.
When To Use Non-Generic Collections?
Non-Generic Collections are older collections in C# and these collections use boxing and unboxing to transfer items into and out of their native types and can hold any object, including value and reference types.
Non-generic collections offer the same actions as generic collections to add, remove, and retrieve items from the collection, but they are constrained in several ways. Their main drawback is that they operate on objects rather than particular types, which can result in runtime errors if the incorrect data type is used.
Non-generic collections contain classes like ArrayList, HashTable, SortedList, Queue, and Stack. These classes offer a variety of data structures, including queues, stacks, associative arrays, dynamic arrays, and queues. However, because of their lack of type safety, they should, whenever possible, be replaced with generic collections and are not advised for use in new code.
When you need to store and manipulate data of various types without having to make separate collections for each type, non-generic collections come in handy. However, they come with some performance costs compared to generic collections, as they need to perform boxing and unboxing operations when storing or retrieving value types.
In legacy code, situations where the data types are unknown at design time, or when interacting with legacy systems, non-generic collections can still be helpful. To improve type safety and performance, it is generally advised to use generic collections.
A list of non-generic collections in C#
- ArrayList
- HashTable
- Queue
- Stack
- BitArray
- SortedList
- Hashtable
- ArrayList.SyncIist
- Queue.SyncQueue
- Stack.SyncStack
- HybridDictionary
- NameValueCollection
- ReadOnlyCollectionBase
- CollectionBase
- DictionaryBase
- StringCollection
- OrderedDictionary
- HybridDictionary
Let’s Explain them:
1. ArrayList
A variable-length array of object references with dynamically changing size is known as an ArrayList. The dynamic arrays that the ArrayList class offers can expand or contract as necessary. With a starting size, an ArrayList is formed. ArrayList can be used in situations when the collection’s size needs to be dynamically adjusted as new elements are added or removed and is not known in advance. The collection automatically grows when this limit is reached. The array gets smaller if items are eliminated.
Using an ArrayList very easily we can add, insert, delete, sort, view, etc. It is very flexible because we can add without any size information, that is, it will grow dynamically and also shrink.
It is also helpful when a group of various types of objects needs to be indexed or ordered-based stored. But with the addition of generic collections in C#, it is typically advised to use ListT> rather than ArrayList due to type safety, improved performance, and more readable code.
Sample codes for ArrayList
`:
ArrayList arrayList = new ArrayList();
arrayList.Add("apple");
arrayList.Add("banana");
arrayList.Add("orange");
arrayList.Remove("banana");
arrayList.Sort();
Console.WriteLine("ArrayList contents: ");
foreach (object obj in arrayList)
{
Console.WriteLine(obj);
}
ArrayList fruits = new ArrayList();
fruits.Add("apple");
fruits.Add("banana");
fruits.Add("cherry");
for (int i = 0; i < fruits.Count; i++)
{
Console.WriteLine(fruits[i]);
}
ArrayList numbers = new ArrayList() { 1, 2, 3, 4, 5 };
if (numbers.Contains(3))
{
Console.WriteLine("3 exists in the ArrayList");
}
else
{
Console.WriteLine("3 does not exist in the ArrayList");
}
ArrayList cars = new ArrayList() { "BMW", "Audi", "Mercedes", "Toyota" };
cars.Clear();
Console.WriteLine("The ArrayList is now empty");
2. HashTable
In C#, a hashtable is a group of key-value pairs that relate keys to values. Keys must be unique. Any item that isn’t null can serve as a key, and any object can serve as a value. Using keys, we can obtain items from hashtables. It is used for fast lookups of data.
Hashtable might be useful when,
- Key-based data storage and retrieval: Hashtable is a good option if you need to store data and rapidly retrieve it using a key. For example, you might use a hashtable with the customer ID as the key to store customer information.
- Avoiding duplication: Using a hashtable can help you keep your collection from containing duplicate objects. Hashtable will check to see if the key already exists before overwriting the value if it does when you add a new key-value combination, and vice versa.
- Performance optimization: The hashtable is designed for quick data access and retrieval. A hashtable can be more effective than an array or list for searching vast amounts of data that you need to access regularly.
- Flexible key types: Unlike some other collection types, hashtables allow you can use any non-null object as a key. If you need to save and access data depending on intricate or specific criteria, this can be helpful.
In general, the generic option which is Dictionary<> is used instead of Hashtable, although they have some differences.
Here are some sample codes of Hashtable
:
Hashtable myHashtable = new Hashtable();
myHashtable.Add("key1", "value1");
myHashtable.Add("key2", "value2");
string value = (string)myHashtable["key1"];
Console.WriteLine(value); // Output: value1
if (myHashtable.ContainsKey("key1"))
{
// key exists in the Hashtable
}
myHashtable.Remove("key1");
foreach (DictionaryEntry entry in myHashtable)
{
string key = (string)entry.Key;
string value = (string)entry.Value;
Console.WriteLine("Key: {0}, Value: {1}", key, value);
}
int count = myHashtable.Count;
myHashtable.Clear();
To be continued…
A Comment or a clap is much appreciated! Thank you for your time!
My some other relevant stories:
Dynamic Memory Allocation VS Static Memory Allocation Common
Difference between “Field” and “Property” in C# OOP
Common Collection Interfaces in C#: A Quick Summary
Singleton Class & Design Pattern in C# OOP
Static Class vs Singleton Class in C# OOP
Default Access Modifiers in C# OOP