C#  

When to Use Generic vs Non-Generic Collections in C#

Collections are a fundamental part of any application that manages data. In C#, you have two primary options for working with collections: generic and non-generic

But what exactly are they, and when should you use one over the other?

In this article, we’ll break down the key differences between the two, highlight their impact on performance and usability.

What Are Collections in C#?

Collections are classes used to store, manage, and manipulate groups of related objects.

These collections fall into two categories:

  • Generic Collections
  • Non-Generic Collections

Generic Collections

Type-Safe by Design

Generic collections require you to define the type of data they will hold. For example, List<int> will only accept integers.

This ensures:

  • No accidental data type mismatches
  • No need for casting

Better Performance

Since there’s no need for boxing/unboxing (converting value types to/from object), generic collections perform faster and use memory more efficiently.

Common Generic Collections

List<string> names = new List<string>(); 
Dictionary<int, string> studentMap = new Dictionary<int, string>();
Queue<double> prices = new Queue<double>(); 
HashSet<Guid> uniqueIds = new HashSet<Guid>();

Non-Generic Collections

Object-Based Storage

Non-generic collections store data as object, which leads to the need for casting when retrieving data.

This can result in:

  • Runtime errors if the cast is incorrect
  • Lower performance due to boxing/unboxing

Common Non-Generic Collections

ArrayList items = new ArrayList();
items.Add(42);
items.Add("hello"); // Works, but can cause issues later

Hashtable map = new Hashtable();
map["id"] = 1;
map["name"] = "Alice";

Performance Comparison

When you work with large amounts of data, the cost of boxing/unboxing and casting becomes significant.

Example

ArrayList list = new ArrayList();
// Value type is boxed
list.Add(1); 
// Unboxed and cast manually
int number = (int)list[0]; 

VS

List<int> list = new List<int>();
// No boxing required
list.Add(1); 
// Clean and safe
int number = list[0]; 

Benchmarking

These are benchmarking result of adding, and iterate throw elements for both type of collections.

Benchmarking

Conclusion

Generic collections are the default choice for modern .NET development providing type safety, clarity, and performance. Non-generic collections still exist for backward compatibility but are largely obsolete for most use cases.

Choose wisely and your application will thank you with fewer bugs and better performance.