If you need to store multiple values in a variable, then you can use a collection.
A collection is a data structure in memory that can manage multiple items in different ways, although all collections have some shared functionality.
There are three main assemblies and namespaces for collections:
System.Collections.dll
assembly and System.Collections.Generic
namespace: The types in this assembly and namespace were introduced in C# 2 with .NET 2.0 and are better because they allow you to specify the type you want to store (which is safer, faster, and more efficient).System.Collections.Concurrent
assembly and namespace: the types in this assembly and namespace are safe to use in multi-threaded scenarios (see Chapter 12, Improving Performance and Scalability with Multitasking).System.Collections.Immutable
assembly and namespace: the types in this assembly and namespace are designed for scenarios where the contents of the collection should never change.All collections have a Count
property to tell you how many items are in it. For example, if we had a collection named passengers
, we could do this:
int howMany = passengers.Count;
All collections can be iterated using the foreach
statement. To perform some action on all the items in the passengers' collection, we can do this:
foreach (var passenger in passengers) { // do something with each passenger }
There are several different collection categories: lists, dictionaries, stacks, queues, sets, and many other more specialized collections.
Lists are a good choice when you want to manually control the order of items in a collection. Each item in a list has a unique index (or position) that is automatically assigned. Items can be any type (although they should all be the same type) and items can be duplicated. Indexes are int
types and start from 0, so the first item in a list is at index 0, as shown in the following table:
Index |
Item |
0 |
London |
1 |
Paris |
2 |
London |
3 |
Sydney |
If a new item (for example, Santiago) is inserted between London and Sydney, then index of Sydney is automatically incremented. Therefore, you must be aware that an item's index can change after inserting or removing items, as shown in the following table:
Index |
Item |
0 |
London |
1 |
Paris |
2 |
London |
3 |
Santiago |
4 |
Sydney |
Dictionaries are a good choice when each value (or item) has a unique subvalue (or a made-up value) that can be used as a key to quickly find the value in the collection later. The key must be unique. If you are storing a list of people, you can use a government-issued identity number as the key.
Think of the key as being like an index entry in a real-world dictionary. It allows you to quickly find the definition of a word because the words (for example, keys) are kept sorted, and if we know we're looking for the definition of Manatee, we would jump to the middle of the dictionary to start looking because the letter M is in the middle of the alphabet. Dictionaries in programming are similarly smart when looking something up.
Both the key and the value can be any type. This example uses strings for both:
Key |
Value |
BSA |
Bob Smith |
MW |
Max Williams |
BSB |
Bob Smith |
AM |
Amir Mohammed |
Stacks are a good choice when you want to implement the last-in, first-out (LIFO) behavior. With a stack, you can only directly access the one item at the top of the stack, although you can enumerate to read through the whole stack of items. You cannot, for example, access the second item in a stack.
For example, word processors use a stack to remember the sequence of actions you have recently performed, and then when you press Ctrl + Z , it will undo the last action in the stack, and then the next last action, and so on.
Queues are a good choice when you want to implement the first-in, first out (FIFO) behavior. With a queue, you can only directly access the one item at the front of the queue, although you can enumerate to read through the whole queue of items. You cannot, for example, access the second item in a queue.
For example, background processes use a queue to process work items in the order that they arrive, just like people standing in line at the post office.
Add a new console application project named Ch04_Lists
.
At the top of the file, import the following namespaces:
using System; using System.Collections.Generic; using static System.Console;
In the Main
method, type the following code that illustrates some of the common ways of working with lists:
The angle brackets after the List<T>
type is a feature of C# called generics. It's just a fancy term for making a collection strongly typed, that is, the compiler knows more specifically what type of object can be stored in the collection. Generics improve the performance and correctness of your code. Strong typed is different from statically typed. The old System.Collection
types are statically typed to contain weakly typed System.Object
items. The newer System.Collection.Generic
types are statically typed to contain strongly typed <T>
instances. Ironically, the term "generics" means a more specific static type!
var cities = new List<string>(); cities.Add("London"); cities.Add("Paris"); cities.Add("Milan"); WriteLine("Initial list"); foreach (string city in cities) { WriteLine($" {city}"); } WriteLine($"The first city is {cities[0]}."); WriteLine($"The last city is {cities[cities.Count - 1]}."); cities.Insert(0, "Sydney"); WriteLine("After inserting Sydney at index 0"); foreach (string city in cities) { WriteLine($" {city}"); } cities.RemoveAt(1); cities.Remove("Milan"); WriteLine("After removing two cities"); foreach (string city in cities) { WriteLine($" {city}"); }
Run the console application to see the output:
Initial list London Paris Milan The first city is London. The last city is Milan. After inserting Sydney at index 0 Sydney London Paris Milan After removing two cities Sydney Paris
Add a new console application project named Ch04_Dictionaries
.
Import the same namespaces as before.
In the Main
method, type the following code that illustrates some of the common ways of working with dictionaries:
var keywords = new Dictionary<string, string>(); keywords.Add("int", "32-bit integer data type"); keywords.Add("long", "64-bit integer data type"); keywords.Add("float", "Single precision floating point number"); WriteLine("Keywords and their definitions"); foreach (KeyValuePair<string, string> item in keywords) { WriteLine($" {item.Key}: {item.Value}"); } WriteLine($"The definition of long is {keywords["long"]}");
Run the application to view the output:
Keywords and their definitions int: 32-bit integer data type long: 64-bit integer data type float: Single precision floating point number The definition of long is 64-bit integer data type
A List<T>
class can be sorted by calling its Sort
method (but remember that the indexes of each item will change).
Sorting a list of strings or other built-in types works automatically, but if you create a collection of your own type, then that type must implement an interface named IComparable
. You will learn how to do this in Chapter 7, Implementing Interfaces and Inheriting Classes.
A Dictionary<T>
, Stack<T>
, or Queue<T>
class cannot be sorted because you wouldn't usually want that functionality, for example, you would never sort a queue of guests checking into a hotel. But sometimes, you might want to sort a dictionary or a set.
The differences between these sorted collections are often subtle, but can have an impact on the memory requirements and performance of your application, so it is worth putting effort into picking the most appropriate for your requirements.
Collection |
Description |
|
This represents a collection of key/value pairs that are sorted on the key |
|
This represents a collection of key/value pairs that are sorted by key, based on the associated |
|
This represents a collection of objects that is maintained in a sorted order |
There are a few other collections for special situations.
Collection |
Description |
|
This manages a compact array of bit values, which are represented as Booleans, where |
|
This represents a doubly-linked list where every item has a reference to its previous and next item |
18.191.165.226