Skip to Content
Course content

193: ToList, ToArray, ToDictionary

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was reviewing a pull request from a junior dev who was building a reporting module. He had a LINQ query that filtered a massive list of transactions for "Pending" status and passed that IEnumerable around to three different methods. The weird part? Each time a method iterated over that list, the results were slightly different because the underlying data source was being updated by another thread. He spent half a day chasing a "ghost bug" before I pointed out that he wasn't actually storing a list of transactions—he was storing the instructions on how to find them. He hadn't materialized the query.

The Deferred Execution Trap

In C#, when you use LINQ methods like Where or Select, you aren't actually executing the filter right then and there. You're creating an IEnumerable, which is essentially a blueprint. This is called deferred execution. It's incredibly powerful for performance, but it can bite you if you assume the data is "frozen" the moment you write the line of code.

This is where ToList(), ToArray(), and ToDictionary() come in. These are called "conversion operators." Their primary job is to force the execution of the query immediately and store the results in a concrete data structure. Once you call ToList(), the query is run, the results are fetched, and you have a snapshot of the data in memory. If the source collection changes a millisecond later, your list stays exactly as it was.

Materializing Your Data

You'll find yourself reaching for ToList() most of the time. It's the Swiss Army knife of materialization. Use it when you need to modify the collection later (like adding or removing items) or when you're passing the data to a piece of code that expects a List<T>. I usually suggest ToList() whenever you plan to iterate over the same filtered result more than once; otherwise, C# will re-run the entire LINQ query every single time you use a foreach loop, which is a silent performance killer.

Then there's ToArray(). In most modern apps, the performance difference between a List and an Array is negligible, but ToArray() is your best bet when you want to signal that the size of the collection is fixed. It's slightly more memory-efficient and tells other developers, "This is a finished set of data; don't try to add things to it."

var activeUsers = allUsers
    .Where(u => u.IsActive)
    .ToList(); // The query runs NOW. The results are frozen in a List.

var topScores = highScores
    .OrderByDescending(s => s.Value)
    .Take(10)
    .ToArray(); // The top 10 are locked into a fixed-size array.


Turning Lists into Maps

Finally, there is ToDictionary(). This is a massive productivity boost when you realize you're doing "lookup loops." If you find yourself writing a foreach loop just to find one specific object in a list by its ID, stop. You should be using a dictionary.

ToDictionary() allows you to specify which property should act as the key and which should be the value. I've used this countless times to optimize API responses—taking a flat list of categories and turning it into a dictionary for O(1) instant lookup. Just be careful: if your source list contains two items with the same key, ToDictionary() will throw an ArgumentException. It demands uniqueness.

// Instead of looping through a list to find a user by ID...
var userMap = allUsers.ToDictionary(u => u.UserId);

// Now you can jump straight to the user without a loop
var myUser = userMap[12345]; 



📋 Practical Task

Exercise: Building a Fast-Lookup Product Catalog

You are working on an e-commerce backend. You have a list of Product objects, but the checkout process is slow because the system is looping through the entire list every time it needs to find a product's price by its SKU (Stock Keeping Unit).

Your task:

  • Create a class Product with properties string SKU, string Name, and decimal Price.
  • Initialize a List<Product> with at least five different products.
  • Use ToDictionary() to convert that list into a dictionary where the SKU is the key and the Product object is the value.
  • Write a small piece of logic that takes a "target SKU" string and uses the dictionary to instantly print the price of that product.
  • Ensure your code handles the case where a SKU might not exist in the dictionary to avoid a KeyNotFoundException.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.