Saturday, June 14, 2025 12:12

Handling exceptions with Try Catch

June 28th, 2018

Usually, when an exception is thrown, the program crashes or begins to malfunction. Fortunately, there is a way to prevent this that allows us to run codes that may generate exceptions, and still safely continue the execution in case of an error. The programming construct that offers us this fail safe is called a Try Catch block. The basic structure of a Try Catch block looks like this:

try
{
    // Some code that may throw an exception
}
catch (ExceptionType objectName)
{
    // Code handling an Exception
}

As you can see, a Try Catch block is composed of two parts: a try block, where we put the codes that might generate exceptions, and one or more Catch block(s), where we handle the exceptions that were caught. ExceptionType must be any type derived from System.Exception namespace, or the program will not compile. You can find some of these types in the lesson about exceptions. Because objectName is a variable just like any other variable, we can use it inside the Catch block to get information related to the caught error.

In the previous lesson, we had this code, that was trying to read a file that was not existing on the disk:

using System;
using System.IO;

namespace HelloWorld
{
    class HelloWorld
    {
        static void Main(string[] args)
        {
            string fileName = "NonExistantTextFile.txt";
            ReadFile(fileName);
            Console.ReadLine();
        }

        static void ReadFile(string fileName)
        {
            StreamReader reader = new StreamReader(fileName);
            string line = reader.ReadLine();
            Console.WriteLine(line);
            reader.Close();
        }
    }
}

And you did see that the code generated an exception when we tried to run it. Let’s now modify it so that it uses a Try Catch block and handles the errors. To do this, all we need to do is wrap the code inside the ReadFile() method inside a Try block, and handle the exceptions that may arise in its Catch block.

using System;
using System.IO;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            string fileName = "NonExistantTextFile.txt";
            ReadFile(fileName);
            Console.ReadLine();
        }

        static void ReadFile(string fileName)
        {
            // Exceptions could be thrown in the code below
            try
            {
                TextReader reader = new StreamReader(fileName);
                string line = reader.ReadLine();
                Console.WriteLine(line);
                reader.Close();
            }
            catch (FileNotFoundException fnfe)
            {
                // Exception handler for FileNotFoundException
                // We just inform the user that there is no such file
                Console.WriteLine("The file '{0}' is not found.", fileName);
            }
            catch (IOException ioe)
            {
                // Exception handler for other input/output exceptions
                // We just print the stack trace on the console
                Console.WriteLine(ioe.StackTrace);
            }
            catch (Exception ex)
            {
                // Exception handler for any other exception that may occur and was not already handled specifically
                // We print the entire exception on the console
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

By doing so, our program will work a bit different. First, because we wrapped the code inside the Try Catch block, when the StreamReader will be initialized with a filename that does not exist, it will no longer make our program crash. Instead, as soon as the Try block detects that an instruction thrown an exception, it will stop the execution inside its block (the remaining code inside the Try block will NOT be executed, after some instruction generated an exception) and transfer it immediately to the Catch block(s). At this point, the compiler will look up what types of exceptions are we handling inside our Catch block(s). If one of the them manages the kind of exception that was thrown, the execution will be transferred to that particular Catch block, where it will run all the code inside it.

In our case, because the StreamReader constructor will throw a FileNotFoundException, the execution will be transferred to the Catch block that handles FileNotFoundException exception types. If the exception would have been of any other type (for instance, file already in use, or insufficient permission to access it), the .NET runtime would look for a different Catch block that would handle that particular exception type, or a type from which the thrown exception is thrown. This is because exceptions are classes, which can be organized in hierarchies, and can inherit one from another (we haven’t learned about inheritance yet); thus, FileNotFoundException is an exception derived from IOException, which is also derived from ApplicationException, which is also derived from Exception, etc. If we didn’t specify a FileNotFoundException handler, but we specified a IOException handler, we would still be fine in case of an exception raised when we try to access a file which does not exist. This happens because IOException is an exception class that is “higher” in the hierarchy compared to the FileNotFoundException one, and FileNotFoundException inherits from it. So, we can say that because other exceptions inherit from IOException, IOException is able to handle more than one kind of exception, just like the Exception class (being the root type of all other types of exceptions, at the very top of the hierarchy) can handle any kind of exception.

So, in our case, since the problematic piece of code raised an exception of type FileNotFoundException and since we declared a Catch block that handles this kind of exceptions, the execution will be transferred immediately to this particular Catch block. As a parameter to this Catch construct, we see that the have a variable called fnfe, of type FileNotFoundException. Just like in a normal function, we can use this parameter variable inside the Catch block:

using System;
using System.IO;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string fileName = "WrongFileName.txt";
                ReadFile(fileName);
            }
            catch (Exception e)
            {
                throw new ApplicationException("Bad thing happened", e);
            }
            Console.Read();
        }

        static void ReadFile(string fileName)
        {
            try
            {
                TextReader reader = new StreamReader(fileName);
                string line = reader.ReadLine();
                Console.WriteLine(line);
                reader.Close();
            }
            catch (FileNotFoundException fnfe)
            {
                Console.WriteLine(fnfe.ToString());
            }
        }
    }
}

In the above code, when the FileNotFoundException exception is thrown, we are using the fnfe variable to print its message on the console using the ToString() method. Be aware, though, this is not considered a good programming practice, and I only exemplified it just so you see that the variable fnfe can be used inside the Catch block. Aside of this, you notice that inside the ReadFile() method we are only handling FileNotFoundException type of exceptions. If ANY other kind of exception would be thrown, it will be passed back to the Main() method, which, also having a Try Catch block that handles the Exception class directly (remember, the Exception class is at the top of hierarchy, it is the parent of all other exceptions, and thus, catches any kind of exception), handles the exception returned by the ReadFile() method. In spite of that, as we will see in a future lesson, using the Exception type directly to catch any kind of exception is also considered a bad programming practice.

Exceptions

June 17th, 2018

In an ideal world, a computer program will execute anything the programmer intended, the way the programmer intended. But since we don’t live in an ideal world (sadly), there are moments when due to the programmer’s mistake or to external conditions, these programs will malfunction or function in a way not intended, causing an exception from what we would normally expect.

An exception is a signal from the software that something disrupted its normal execution. For instance, we might want to download a file from a server. But halfway through, the internet connection goes down and the download cannot continue. This is considered an exception.

Although most beginner programmers fear and loath exceptions, experience teaches us that they are mere tools that can help us in detecting, interacting and correcting abnormal behaviors. When an exception occurs, the current state of the program is saved, the execution is halted and the control is passed to an exception handler, if such thing exist in that context. Exceptions are accompanied by an error message which can help us identify what went wrong in the program. Programmers say that an exception is raised or thrown.

Exception handlers are programming mechanisms that allow the program to throw exceptions and catch them. In procedural programming, methods and functions usually return a value which can be used for error signaling. In OOP, exceptions offer a better way of dealing with errors, and consequently, methods and functions are able to throw and catch errors themselves, or to pass the exception to the method that called them. This allows errors to be propagated higher in the execution stack and hence make the code much more flexible. Another good thing in OOP is that exceptions are actually classes, and such we can have exceptions hierarchies. We haven’t yet learned about inheritance, but suffice to say that when an exception is handled (caught), the handling mechanism could catch a whole class of exceptions and not just a particular error (as in the traditional procedural programming). In other words, we can catch multiple types of errors at the same time, in a centralized manner.

Exceptions are objects. They describe the error, offer information about it, show the place in the program where the error occurred and the state of the program when that error occurred. Each exception in .NET contains the so-called stack trace, which gives information of where exactly the error occurred. This will be discussed in more details later on.

Lets take an example of a code that will throw an exception:

using System;
using System.IO;

namespace HelloWorld
{
    class HelloWorld
    {
        static void Main(string[] args)
        {
            string fileName = "NonExistantTextFile.txt";
            ReadFile(fileName);
            Console.ReadLine();
        }

        static void ReadFile(string fileName)
        {
            StreamReader reader = new StreamReader(fileName);
            string line = reader.ReadLine();
            Console.WriteLine(line);
            reader.Close();
        }
    }
}

The above code will try to read a file from the disk, at a path we are providing as an argument to the function that performs the reading. We haven’t learned about dealing with files yet, but it is OK for the moment. The compiler will not complain about any errors, because there are none. For what its worth, from the compiler’s perspective, there is nothing wrong with that code. However, when we try to run this program from Windows Explorer, the output will look like this:

Trying to run the code from within Visual Studio will generate the same exception, but the behavior will be different. Visual Studio will actually show us the occurring exception:

FileNotFoundException

 

If this program was a GUI application, the runtime behavior would be different again. We would get this:

and we probably all know what that means…

The problem was that there is no file at the path we provided to that method. And this generates an exception. Another thing that we observe from the above photos is the fact that the compiler not only shows us the line at which the error occurred, but it also shows us details about the error, such as its name and some description about it. We now know that there are more than one type of exceptions and they have names. The most frequent exceptions that you will encounter as a programmer are the following:

AccessViolationException – The exception that is thrown when there is an attempt to read or write protected memory.
ApplicationException – The exception that is thrown when a non-fatal application error occurs.
ArgumentException – The exception that is thrown when one of the arguments provided to a method is not valid.
ArgumentNullException – The exception that is thrown when a null reference is passed to a method that does not accept it as a valid argument.
ArgumentOutOfRangeException – The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the called method.
ArithmeticException – The exception that is thrown for errors in an arithmetic, casting, or conversion operation.
DivideByZeroException – The exception that is thrown when there is an attempt to divide an integral or decimal value by zero.
DllNotFoundException – The exception that is thrown when a DLL specified in a DLL import cannot be found.
IndexOutOfRangeException – The exception that is thrown when an attempt is made to access an element of an array with an index that is outside the bounds of the array.
InsufficientMemoryException – The exception that is thrown when a check for sufficient available memory fails. This class cannot be inherited.
InvalidCastException – The exception that is thrown for invalid casting or explicit conversion.
NotFiniteNumberException – The exception that is thrown when a floating-point value is positive infinity, negative infinity, or Not-a-Number (NaN).
NullReferenceException – The exception that is thrown when there is an attempt to dereference a null object reference.
ObjectDisposedException – The exception that is thrown when an operation is performed on a disposed object.
OutOfMemoryException – The exception that is thrown when there is not enough memory to continue the execution of a program.
OverflowException – The exception that is thrown when an arithmetic, casting, or conversion operation in a checked context results in an overflow.
StackOverflowException – The exception that is thrown when the execution stack overflows because it contains too many nested method calls.
TimeoutException – The exception that is thrown when the time allotted for a process or operation has expired.
UnauthorizedAccessException – The exception that is thrown when the operating system denies access because of an input/output (I/O) error or a specific type of security error.
KeyNotFoundException – The exception that is thrown when the key specified for accessing an element in a collection does not match any key in the collection.
DirectoryNotFoundException – The exception that is thrown when part of a file or directory cannot be found.
DriveNotFoundException – The exception that is thrown when trying to access a drive or share that is not available.
EndOfStreamException – The exception that is thrown when reading is attempted past the end of a stream.
FileNotFoundException – The exception that is thrown when an attempt to access a file that does not exist on disk fails.
IOException – The exception that is thrown when an I/O error occurs.
PathTooLongException – The exception that is thrown when a path name or filename is longer than the system-defined maximum length.
COMException – The exception that is thrown when an unrecognized HRESULT is returned from a COM method call.
InvalidComObjectException – The exception thrown when an invalid COM object is used.
SerializationException – The exception thrown when an error occurs during serialization or deserialization.
SecurityException – The exception that is thrown when a security error is detected.
XmlSyntaxException – The exception that is thrown when there is a syntax error in XML parsing. This class cannot be inherited.
HttpException – Describes an exception that occurred during the processing of HTTP requests.
HttpParseException – The exception that is thrown when a parse error occurs.
SocketException – The exception that is thrown when a socket error occurs.

You don’t need to memorize this list, just keep it as a reference whenever you encounter exceptions.

In the next lesson, we will talk about handling exceptions, so they don’t break our programs when they occur, and put them to good use for us.

Other Data Structures

June 16th, 2018

Surprisingly, you will notice that we have already used these data structures before, without knowing they were data structures: the class and the structure. Whenever we instantiate one of these, we are actually using it as a data structure (more or less). You may not know, but a structure is very similar to a class, in the way we declare and use it. Both can have field variables, both can contain methods, both can be instantiated, etc. The only difference between a class and a struct is the way they work internally. We haven’t learned about stack (no, not the stack data structure) and heap, but basically they are two different kinds of memory in the RAM of your computer, with different behaviors. So, a class, being a reference type, is stored as a pointer, a reference to some other place in the heap, where the actual value is stored. On the other hand, a structure, being a value type, is stored on the stack, and the variable holds the entire data itself, with all its fields, methods, etc. Another difference is the fact that reference types can be null (they point to no place in the memory), while value types always contain a value.

According to MSDN: “structs are typically used to encapsulate small group of related variables, such as coordinates of rectangle. Structs can also contain constructors, constants, fields, methods, properties, indexers, operators, events, and nested types, although if several such members are required, you should consider making your type a class instead.”

This means that whenever you just need to store simple data, a struct is perfect for the job. But if you find yourself adding functionality and logic to your structure, it would most likely be better to make it a class.

Now, lets see how we can use both these concepts as data structures:

using System;

namespace HelloWorld
{
    struct Point
    {
        public int X;
        public int Y;
    }

    class Size
    {
        public int width;
        public int height;
    }

    class Program
    {
        static void Main()
        {
            // create a new structure instance
            Point newPoint = new Point();
            newPoint.X = 5;
            newPoint.Y = 8;

            // create a new class instance
            Size newSize = new Size();
            newSize.width = 4;
            newSize.height = 9;

            Console.ReadLine();
        }
    }
}

As you can notice, at this point, we are actually storing data inside our newPoint and newSize variables. We could store names, addresses, whatever we would want.

The only “downside” compared to other data structures is the fact that if we want to store another field, we need to modify the class or struct itself. This means that once our code is compiled and executed, we cannot modify the structure of our class or struct. We cannot add another variable called “length” to our Size class. On the other side, for the other data structures (such as dictionary, list, etc), adding a new value to the class at runtime is just a matter of using the Add() method. The “advantage” is the fact of being able to store multiple data types in a single data structure, unlike arrays, lists, etc, and also having the possibility of acting upon that data (methods, functions, etc) internally.

Sorted Set

June 16th, 2018

Sorted Set is the preferred data structure when we want to have sorted items and also to eliminate duplicate elements. Unfortunately, its performance is worse than that of a Hash Set or a Dictionary. The following program declares a new Sorted Set and adds elements to it:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Create a new sorted set of strings.
        SortedSet<string> set = new SortedSet<string>();

        // Add 4 elements.
        set.Add("cat");
        set.Add("dog");
        set.Add("cow");
        set.Add("horse");

        // Remove an element.
        set.Remove("cat");

        // Print elements in set.
        foreach (string element in set) // will print in alphabetical order
            Console.WriteLine(element);
        Console.ReadLine();
    }
}

Sometimes happens that you may want to create a Sorted Set from the elements contained in another data structure, such as an array or list. This can be accomplished directly using the Sorted Set’s constructor:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Create list with elements of type string, with duplicates.
        List<string> list = new List<string>();
        list.Add("cat");
        list.Add("dog");
        list.Add("chicken");
        list.Add("chicken");

        // Create a sorted set from list using the constructor.
        SortedSet<string> set = new SortedSet<string>(list);

        // Display contents.
        foreach (string element in set)
            Console.WriteLine(element);
        Console.ReadLine();
    }
}

The most useful methods of the Sorted Set class are the following:

RemoveWhere() – this method can be used to remove all elements that meet a certain condition. This method uses Linq, of which we haven’t learned yet:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Create a sorted set.
        SortedSet<string> set = new SortedSet<string>();
        set.Add("jane");
        set.Add("sarah");
        set.Add("adam");
        set.Add("ben");
        set.Add("mark");
        set.Add("mark");

        // Remove all elements where first letter is "m".
        set.RemoveWhere(element => element.StartsWith("m"));

        // Display results
        foreach (string element in set)
            Console.WriteLine(element);
        Console.ReadLine();
    }
}

Clear() – Just as in the case of the other data structures we learned so far, Clear() can be used to remove all the elements in the collection.
UnionWith() – As in the case of the Hash Set, this method will return a new collection of sorted elements by merging two other collections, of course, removing the elements that are duplicates.
SymmetricExceptWith() – This method will join two collections by taking all the elements that are unique to one of the collections. So, all the elements that are found in one of the collections, but not in the other.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        SortedSet<string> set = new SortedSet<string>();
        set.Add("a");
        set.Add("z");
        set.Add("x");

        List<string> list = new List<string>();
        list.Add("a");
        list.Add("y");

        // Determine symmetric set.
        set.SymmetricExceptWith(list);

        // Display elements.
        foreach (string element in set)
            Console.WriteLine(element);
        Console.ReadLine();
    }
}

ExceptWith() – This is a subtracting method. It will take two collections and will return all the elements that are not present in one of them.
Overlaps() – This useful method tells us if a collection has any elements in common with our Sorted Set. If at least one element is found in both of them, the result is True, otherwise False.
IntersectWith() – Method for merging two collections by taking all the elements that are present in both of them.
Min(), Max() – Since you cannot use an index to access the elements of a Sorted Set, these methods are useful in the sense that they can offer us the first or the last elements of the collection.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Declare a new sorted set and add few elements
        var set = new SortedSet<string>();
        set.Add("a");
        set.Add("f");
        set.Add("z");
        set.Add("x");

        // Display Min and Max values of the collection
        Console.WriteLine(set.Min);
        Console.WriteLine(set.Max);
        Console.ReadLine();
    }
}

The output will be:

Sorted Set

IsSubsetOf(), IsSupersetOf(), IsProperSubsetOf() and IsProperSupersetOf() – These are methods that help us compute subsets and supersets. In common language, a subset is a set that is contained entirely inside another set. A superset is the set that contains entirely another set. Aside of that, “proper subset” or “proper superset” refers to the property of not having the same exact count of elements. A superset must have at least one element more than the contained set, and a subset must have at least one element less than the set containing it:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var set = new SortedSet<string>();
        set.Add("a");
        set.Add("z");
        set.Add("x");

        var list1 = new List<string>();
        list1.Add("a");
        list1.Add("z");
        list1.Add("x");

        var list2 = new List<string>();
        list2.Add("a");
        list2.Add("z");
        list2.Add("x");
        list2.Add("y");

        Console.WriteLine("IsProperSubsetOf: {0}", set.IsProperSubsetOf(list1));
        Console.WriteLine("IsSubsetOf: {0}", set.IsSubsetOf(list1));

        Console.WriteLine("IsProperSubsetOf: {0}", set.IsProperSubsetOf(list2));
        Console.WriteLine("IsSubsetOf: {0}", set.IsSubsetOf(list2));

        var list3 = new List<string>();
        list3.Add("a");
        list3.Add("z");

        Console.WriteLine("IsProperSupersetOf: {0}", set.IsProperSupersetOf(list3));
        Console.WriteLine("IsSupersetOf: {0}", set.IsSupersetOf(list3));
        Console.ReadLine();
    }
}

Producing this result:

SetEquals() – An useful methods whenever we want to compare two Sorted Sets and check whether they contain the same elements.
GetViewBetween() – a method for taking all the elements in a Sorted Set, between two of its elements, which we provide as parameters to this method. The returned elements are all the elements that are found between these two elements (including them).

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var set = new SortedSet<int>();
        set.Add(5);
        set.Add(7);
        set.Add(8);
        set.Add(9);
        set.Add(4);

        // Call GetViewBetween method.
        SortedSet<int> view = set.GetViewBetween(4, 7);

        foreach (int element in view)
            Console.WriteLine(element);
        Console.ReadLine();
    }
}

The above program will display 4, 5, 7. Why? Because, remember, this is a Sorted Set. So, even if we added the elements in a random order, they will be sorted (numerically, in this case, because we supplied integers). And, after sorting them, the elements that are found between 4 and 7 inclusive, are 4, 5 and 7.

Contains() – Determines whether a Sorted Set contains a certain element.

The most important property of a Sorted Set is:

Count – returns the number of elements in the collection.

Hash Set

June 14th, 2018

There are two types of Sets in the System.Collections.Generic namespace: SortedSet and HashSet. Both of them offer the functionality of storing non-duplicate items. The main difference between them is the fact that the SortedSet obviously has its items sorted. Therefor, if you do not care about the order in which the items are stored, you are better off performance-wise to use a HashSet. It will be slightly faster. In comparison with a List, a HashSet has a bit slower adding of elements. However, searching, reading or deleting elements is much, much faster, due to the hashing of the elements.

HashSet doesn’t have a capacity set. Its capacity increases along with the addition of elements.

We can directly assign the elements of an array to a HashSet, and the duplicate entries will be removed:

using System;
using System.Collections.Generic;
 
namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Using HashSet");
            // Define an array of type string (notice the duplicate elements!) 
            string[] names = new string[] 
            {
                "cat",
                "dog",
                "cat",
                "bird",
                "cow",
                "horse",
                "cat"
            };

            // Print the length of the array and its elements
            Console.WriteLine("Length of Array " + names.Length);
            Console.WriteLine();
            Console.WriteLine("The Data in Array");
            foreach (var n in names)
                Console.WriteLine(n); 
            Console.WriteLine();

            // Define a HashSet by passing the string array to it
            HashSet<string> hashSet = new HashSet<string>(names);
            // Display count of elements in HashSet
            Console.WriteLine("Count of elements in HashSet " + hashSet.Count);
            Console.WriteLine();

            // Print the elements in the HashSet, proving that the duplicate element "cat" was removed 
            Console.WriteLine("Data in HashSet");
            foreach (var n in hashSet)
                Console.WriteLine(n);
            Console.ReadLine();
        }
    }
}

The HashSet object does not allow duplicate entry, hence the result will show the count of the data present in the HashSet less than the array count. The output will look like this:

The most important methods of the HashSet class are the following:

UnionWith() – we can use this method to union (join) the elements already contained in a HashSet with the elements of another collection.

using System;
using System.Collections.Generic;

namespace HelloWorld
{
    class Program
    {
        private static void Main(string[] args)
        {
            string[] names1 = new string[] { "John", "Walter", "John", "Cristopher", "James", "Connor" };
            string[] names2 = new string[] { "Jane", "Sarah", "Eddie", "Maria", "John", "Sarah" };

            HashSet<string> hashSet1 = new HashSet<string>(names1);
            Console.WriteLine("Data in First HashSet");
            foreach (var name in hashSet1)
                Console.WriteLine(name);
            Console.WriteLine("_______________________________________________________________");
            HashSet<string> hashSet2 = new HashSet<string>(names2);

            Console.WriteLine("Data in Second HashSet");
            foreach (var name in hashSet2)
                Console.WriteLine(name);
            Console.WriteLine("________________________________________________________________");
            Console.WriteLine("Data After Union");
            hashSet1.UnionWith(hashSet2);
            foreach (var n in hashSet1)
                Console.WriteLine(n);
            Console.ReadLine();
        }
    }
}

The result would be:

Notice that the duplicate elements were removed from the merged HashSet.

ExceptWith() – This method is the complementary of UnionWith() – it will remove all the elements that are contained in both data structures, including the duplicate elements.

SymmetricExceptWith() – This modifies the final HashSet to include only the results that are present in one of the HashSet, but not both. All the matching elements will be removed.

The most important property of the HashSet is:

Count – returns an integer representing the total number of elements in the HashSet.

Sorted Dictionary

June 8th, 2018

Sorted Dictionary is just a normal Dictionary data structure, but with its keys sorted. Of course, it is obvious that having its elements sorted will make this data structure slightly slower than a normal Dictionary, but it does offer the advantage of making an in memory sorted lookup very easy.

To better understand how a Sorted Dictionary works, let’s create a code where we will add a few elements in random order, and then we will lookup some of the keys:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Create a new SortedDictionary
        SortedDictionary<string, int> sortedDictionary = new SortedDictionary<string, int>();

        // Add some elements, in random order
        sortedDictionary.Add("zebra", 5);
        sortedDictionary.Add("cat", 2);
        sortedDictionary.Add("dog", 9);
        sortedDictionary.Add("mouse", 4);
        sortedDictionary.Add("programmer", 100);

        // Check if dictionary contains "dog" key
        if (sortedDictionary.ContainsKey("dog"))
            Console.WriteLine(true);

        // See if it contains "zebra"
        if (sortedDictionary.ContainsKey("zebra"))
            Console.WriteLine(true);

        // Example: see if it contains "ape"
        Console.WriteLine(sortedDictionary.ContainsKey("ape"));

        // Example: see if it contains "programmer", and if so get the value for "programmer"
        int v;
        if (sortedDictionary.TryGetValue("programmer", out v))
            Console.WriteLine(v);

        // Example: print SortedDictionary elements in alphabetic order
        foreach (KeyValuePair<string, int> p in sortedDictionary)
            Console.WriteLine("{0} = {1}", p.Key, p.Value);
    }
}

The output code will look like this:

In the code above, we used the TryGetValue() method, which spared us of using another instruction, bu first checking if the key exists, and then assigning its value to the v variable, when this element was found. Finally, we used a foreach loop to iterate through the elements of the sorted dictionary.

Be aware that the performance of Sorted Dictionary degrades rapidly when we start adding a lot of elements.

Note that there is also a SortedList collection in the System.Collections.Generic namespace. This provides essentially the same functionality as the SortedDictionary but with a different internal implementation. The SortedList has different performance characteristics, particularly when inserting or removing elements from the collection.

Dictionary

June 1st, 2018

The data structure Dictionary suggests storing key-value pairs and provides a quick search by key. In common language, this means that instead of elements receiving a numerical index, as in the array case, they receive a specific type as a key (this is what the K stands for in the Dictionary<K, T> concept; T stands for the type of the values stored in the dictionary) for accessing elements. Most of the times, this key is a string – and this allows us to give names to our elements. So, instead of accessing the fifth element of an array by using the integer 4 as the “key” (remember, arrays are 0 index based!), we can access the fifth element by the value we gave to its key, which could be a word, for instance. Just like in a real dictionary, we search for a specific word (which is the “key”), and when we find it, we read the definition of that word (which is the stored “value” for that element). Just like in a real dictionary, we are not allowed to have more than one element with the same key (in a real dictionary, a word is not defined twice).

Dictionary, along with the List, are the most important and used data structures (except maybe for the array). The implementation with a hash table (the class Dictionary<K, T>) has a very fast add, search and remove of elements – constant complexity at the average case. The operation access through index is not available, because the elements in the hash-table have no order, i.e. an almost random order. Dictionary<K, T> keeps internally the elements in an array and puts every element at the position calculated by the hash-function. Thus the array is partially filled – in some cells there is a value, others are empty. If more than one element should be placed in a single cell, elements are stored in a linked list. It is called chaining. This is one of the few ways to resolve the collision problem. When the dictionary number of elements exceeds 75% of its capacity, the size is doubled and all the elements occupy new positions. This operation has a linear complexity, but it is executed so rarely, that the amortized complexity remains a constant. Hash-table has one peculiarity: if we choose a bad hash-function causing many collisions, the basic operations can become very inefficient and reach linear complexity. In practice, however, this hardly happens. Hash-table is considered to be the fastest data structure, which provides adding and searching by key. Hash-table in .NET Framework permits each key to be put only once. If we add two elements with the same key consecutively, the last will replace the first and we will eventually lose an element. This important feature should be considered.

From time to time one key will have to keep multiple values. This is not standardly supported, but we can store the values matching this key in a List as a sequence of elements. For example if we need a hash-table Dictionary<int, string>, in which to accumulate pairs {integer, string} with duplicates, we can use Dictionary<int, List<string>>. Some external
libraries have ready to use data structure called MultiDictionary<K, V>. Hash-table is recommended to be used every time we need fast addition and fast search by key. For example if we have to count how many times each word is encountered in a set of words in a text file, we can use Dictionary<string, int> – the key will be a particular word, the value – how many times we have seen it. Use a dictionary when you want to add and search by key very fast.

Since dictionaries are generic, the types of the key and value must be specified when creating a dictionary, for example:

Dictionary<string, int> dictionary = new Dictionary<string, int>();

The above line of code will create a new dictionary in which the keys will be strings, and the stored values will be integers.

Adding data to a dictionary is similar to adding values to a List, except that it takes a key and value argument:

dictionary.Add("one", 1);

Once data is stored inside a C# dictionary, you use the key values as indices to retrieve values. To put it in context, a List uses numbers as keys (indices) to get its values, while a Dictionary uses the defined keys:

int one = dictionary["one"];

Traversing a dictionary (going through each element) is tricky because the keys can be anything within its data type. The only way to access all the values in a C# dictionary is to know all the keys. That is when the Keys property comes in, which holds a collection of any key added. Here is an example on iterating through a C# dictionary:

//declare a new dictionary with keys of type string and values of type int
Dictionary<string, int> dictionary = new Dictionary<string, int>();

//add two elements
dictionary.Add("one", 1);
dictionary.Add("two", 2);

//declare a new list of type string by casting the Keys property of the dictionary
List<string> keys = new List<string>(dictionary.Keys);

//loop through the new list
for (int i = 0; i < keys.Count; i++)
    int j = dictionary[keys[i]];

Two things to consider: insertion time and searching time. Because elements are not automatically sorted, inserting elements is faster. Similarly because elements are not sorted, it makes searching more complicated, meaning searching is slower.

To better understand how a dictionary uses the concepts of keys and values, let’s take the following example:

Dictionary<string, int> commonPhysicsValues = new Dictionary<string, int>();
commonPhysicsValues.Add("WaterBoilingTemperature", 100);
commonPhysicsValues.Add("WaterFreezingTemperature", 0);
commonPhysicsValues.Add("AbsoluteZero", -273);
commonPhysicsValues.Add("LeadMeltingPoint", 327);

Console.WriteLine(commonPhysicsValues["WaterFreezingTemperature"]);

So, we declared a new Dictionary of type string-int, and we added few physics constants, like the boiling and freezing temperature of water. We could add those values in an array too, but it would become extremely difficult to remember what all the values represent, specially when they get many. And not to mention duplicate values.. who can tell what they each represent? So, in this case, by using a dictionary and giving significant names to the keys, we can easily access the values by their corresponding key, and also know what those values represent, at the same time. The only rule we have to obey is not having duplicate keys. If we try to add a key that already exists, Visual Studio will generate an exception of type System.ArgumentException: ‘An item with the same key has already been added.’.

The most important methods of the Dictionary class are:

ContainsKey() – will check if a given key string is present in the dictionary. It will return True if the key was found, or False otherwise.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> dictionary = new Dictionary<string, int>();

        dictionary.Add("apple", 1);
        dictionary.Add("windows", 5);

        // See whether Dictionary contains this string.
        if (dictionary.ContainsKey("apple"))
        {
            int value = dictionary["apple"];
            Console.WriteLine(value);
        }

        // See whether it contains this string.
        if (!dictionary.ContainsKey("orange"))
        {
            Console.WriteLine(false);
        }
    }
}

TryGetValue() – This is actually the recommended way of checking whether a key is present in a dictionary or not. If the key exists, it will return its value.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, string> values = new Dictionary<string, string>();

        values.Add("cat", "feline");
        values.Add("dog", "canine");

        // Use TryGetValue.
        string test;
        if (values.TryGetValue("cat", out test)) // Returns true.
        {
            Console.WriteLine(test); // This is the value at cat.
        }
        if (values.TryGetValue("bird", out test)) // Returns false.
        {
            Console.WriteLine(false); // Not reached.
        }
    }
}

ContainsValue() – This method lacks the constant-time look up speed of ContainsKey. It instead searches the entire collection. It is linear in complexity. It will loop through all elements in the Dictionary until it finds a match, or there are no more elements to check.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("cat", 1);
        d.Add("dog", 2);
        if (d.ContainsValue(1))
            Console.WriteLine(true); // True.
    }
}

Clear() – This will clear all the keys and value pair in the dictionary. The same result can be achieved by assigning the dictionary to null.

Remove() – It will remove a specific element that we pass as an argument to this method. In case the key doesn’t exist, it will do nothing.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        d.Add("cat", 1);
        d.Add("dog", 2);

        d.Remove("cat"); // Removes cat.
        d.Remove("nothing"); // Doesn't remove anything.
    }
}

Count() – will return an int representing the number of elements in the dictionary.

Equals() – We can use this method to check whether two dictionaries are identical.

The property that is most used WITH the Dictionary class is:

Keys – The Keys property returns a collection of type KeyCollection, not an actual List. We can convert it into a List.

Be aware that if we try to directly access a key that does not exist, we will get an exception called KeyNotFoundException. With Dictionary we must test keys for existence first, with ContainsKey or TryGetValue.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<string, string> test = new Dictionary<string, string>();
        test.Add("one", "value");

        string value;
        // Use TryGetValue to avoid KeyNotFoundException.
        if (test.TryGetValue("two", out value))
            Console.WriteLine("Found");
        else
            Console.WriteLine("Not found");
    }
}

Queue

May 28th, 2018

Queue is a linear data structure in which there are two operations defined: adding an element to the tail (enqueue) and extract the front-positioned element from the head (dequeue). These two operations take a constant time to execute, because the queue is usually implemented with a linked list. I remind you that the linked list can quickly add and remove elements from its
both ends. The queue’s behavior is FIFO (first in, first out). The operations searching and accessing through index are not supported. Queue can naturally model a list of waiting people, tasks or other objects, which have to be processed in the same order as they were added (enqueued).

As an example of using a queue, I can point out the implementation of the BFS (breadth-first search) algorithm, in which we start from an initial element and all its neighbors are added to a queue. After that they are processed in the order they were added and their neighbors are added to the queue too. This operation is repeated until we reach the element we are looking for or we process all elements.

The call to add elements for a queue (or the Push version) is Enqueue():

queue.Enqueue("1");

The reverse operation of removing items is accomplished using the Dequeue() method:

queue.Dequeue();

Similarly, the Peek() call allows you to view the top value without removing it. This specific data structure is very often used in conjuncture with stack data structures.

Keep in mind the queue data structure can be defined as a general Queue and as a type-specific Queue<T>.

The most important methods of the Queue data structure are:

Copy(), CopyTo() – Allows us to copy Queue elements. We might have a Queue collection but need to loop over the elements in the reverse order. We call CopyTo(), and then loop over the array in reverse. We use CopyTo() with an int array. We allocate the number of elements to the int[] with the same integer as the Queue’s Count property.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // New Queue of integers.
        Queue<int> queue = new Queue<int>();
        queue.Enqueue(5);
        queue.Enqueue(10);
        queue.Enqueue(15);
        queue.Enqueue(20);

        // Create new array with Length equal to Queue's element count.
        int[] array = new int[queue.Count];

        // Copy the Queue to the int array.
        queue.CopyTo(array, 0);

        // Loop through and display int[] in order.
        Console.WriteLine("Array:");
        for (int i = 0; i < array.Length; i++) 
            Console.WriteLine(array[i]); 

        // Loop through int array in reverse order. 
        Console.WriteLine("Array reverse order:"); 
        for (int i = array.Length - 1; i >= 0; i--)
            Console.WriteLine(array[i]);
        Console.ReadLine();
    }
}

The output looks like this:

Clear() – Use this method to remove all elements from the Queue. This can be used instead of assigning the reference to a new Queue.
Contains() – You can use Contains() to search through the Queue for a matching element. This method does a linear search.
Dequeue() – Removes the object at the beginning of your Queue. It doesn’t loop over elements.
Peek() – Returns the object at the beginning of the Queue(T) without removing it. This means you only look at the object.
ToArray() – Converts your Queue(T) to an array. This is similar to CopyTo(), but it provides the new array reference.

The most important property of the queue is:

Count – Returns the number of elements. It requires constant time and doesn’t enumerate the elements.

Stack

May 2nd, 2018

Stack is a linear data structure in which there are 3 operations defined: adding an element at the top of the stack (push), removing an element from the top of the stack (pop) and inspect the element from the top without removing it (peek). All these operations are very fast – it takes a constant time to execute them. The stack does not support the operations search and
access through index. The stack is a data structure which has a LIFO behavior (last in, first out). It is used when we have to model such a behavior – for example, if we have to keep the path to the current position in a recursive search. Use a stack when you have to implement the behavior “last in, first out” (LIFO).

Like an List, a stack has an add and get method, with a slight difference in behavior.

To add to a stack data structure, you need to use the Push() call, which is the Add() equivalent of an List. Retrieving a value is slightly different. The stack has a Pop() call, which returns and removes the last object added. If you want to check the top value in a Stack, use the Peek() call.

There are two formats to define a Stack in C#:

Stack stack = new Stack();
Stack<string> stack = new Stack<string>();

The difference between them is that the simple Stack structure will work with Objects, while the Stack<T> one will accept only a specified type.

Here is the C# code to add and traverse through a Stack data structure:

Stack<string> stack = new Stack<string>();
stack.Push("one");
stack.Push("two");
stack.Push("three");

while (stack.Count > 0)
    Console.WriteLine(stack.Pop());

If you run the above C# code, you see that the list is returned in the order: “three”, “two”, “one”.

These are the main methods of a Stack:

Push() – Usually the first action you need to do on Stack is Push elements into it. The word Push is a computer science term that means “add to the top.”

using System;
using System.Collections.Generic;

class Program
{
    static Stack<int> GetStack()
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(100);
        stack.Push(1000);
        stack.Push(10000);
        return stack;
    }

    static void Main()
    {
        var stack = GetStack();
        Console.WriteLine("--- Stack contents ---");
        foreach (int i in stack)
            Console.WriteLine(i);
    }
}

Pop(), Peek() – Here we Pop and Peek. When you call Pop(), the elements from the top of the Stack is returned, and the element is removed from the collection.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Get the stack.
        Stack<int> stack = GetStack();

        // Pop the top element.
        int pop = stack.Pop();

        // Write to the console.
        Console.WriteLine("--- Element popped from top of Stack ---");
        Console.WriteLine(pop);

        // Now look at the top element.
        int peek = stack.Peek();
        Console.WriteLine("--- Element now at the top ---");
        Console.WriteLine(peek);
    }

    static Stack<int> GetStack()
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(100);
        stack.Push(1000);
        stack.Push(10000);
        return stack;
    }
}

Clear() – is a parameterless method. It erases the Stack’s contents.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Get the stack
        Stack<int> stack = GetStack();

        // Count the number of elements in the Stack
        int count = stack.Count;
        Console.WriteLine("--- Element count ---");
        Console.WriteLine(count);

        // Clear the Stack
        stack.Clear();
        Console.WriteLine("--- Stack was cleared ---");
        Console.WriteLine(stack.Count);
    }

    static Stack<int> GetStack()
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(100);
        stack.Push(1000);
        stack.Push(10000);
        return stack;
    }
}

Contains() – We search the Stack with the Contains() method. The Contains method on Stack returns true if the element is found.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // An example string array.
        string[] values = { "one", "two", "three" };

        // Copy an array into a Stack.
        var stack = new Stack<string>(values);

        // Display the Stack.
        Console.WriteLine("--- Stack contents ---");
        foreach (string value in stack)
            Console.WriteLine(value);

        // See if the stack contains "three"
        Console.WriteLine("--- Stack Contains method result ---");
        bool contains = stack.Contains("three");
        Console.WriteLine(contains);
    }
}

The most important property of a Stack is:

Count – gives the number of elements in a Stack.

The value null is allowed in Stacks with reference types such as string. You can also assign your Stack to null instead of calling Clear(). When assigning to null, the contents are not changed. Instead the reference is unrooted in the garbage collector. When you call Pop() or Peek() on your Stack, the runtime will throw an exception if the Stack has zero elements. To work around this problem, you must check the Count property. Here we catch the exception raised by this situation (we haven’t learn about exceptions yet, but just consider them a special kind of errors):

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Create an empty Stack.
        var stack = new Stack<int>();

        try
        {
            // This throws an exception.
            int pop = stack.Pop();
        }
        catch (Exception ex)
        {
            Console.WriteLine("--- Exception raised by Pop ---");
            Console.WriteLine(ex.ToString());
        }

        // Here we safely Pop the stack.
        if (stack.Count > 0)
            int safe = stack.Pop();
        else
            Console.WriteLine("--- Avoid exceptions by using Count method! ---");
    }
}

List

May 1st, 2018

Dynamic list (List<T>) is one of the most popular data structures used in programming. It does not have fixed size like arrays, and allows direct access through index, unlike linked lists (LinkedList<T>). The dynamic array is also known as “array list”, “resizable array” and “dynamic array”. List<T> holds its elements in an array, which has a bigger size than the count of the stored elements. Usually when we add an element, there is an empty cell in the list’s inner array. Therefore, this operation takes a constant time. Occasionally, the array fills, and it has to expand. This takes linear time, but it rarely happens. If we have a large amount of additions, the average-case complexity of adding an element to List<T> will be a constant. If we sum the steps needed for adding 100,000 elements (for both cases – “fast add” and “add with expand”) and divide by 100,000, we will obtain a constant which will be nearly the same for like adding 1,000,000 elements.

This statistically-averaged complexity calculated for large enough amount of operations is called amortized complexity. Amortized linear complexity means that if we add 10,000 elements consecutively, the overall count of steps will be of the order of 10,000. In most cases add it will execute in a constant time. Searching in List<T> is a slow operation because you have to traverse
through all the elements. Removing by index or value executes in a linear time. It is a slow operation because we have to move all the elements after the deleted one with one position to the left.
The indexed access in List<T> is instant, in a constant time, since the elements are internally stored in an array. Practically, List<T> combines the best of arrays and lists, this being the reason for which it is a preferred data structure in many situations. For example if we have to process a text file and to extract from it all words (with duplicates), which match a regular expression, the most suitable data structure in which we can accumulate them is List<T>, because we need a list, the length of which is unknown in advance and can grow dynamically. The dynamic array (List<T>) is appropriate when we have to add elements frequently, as well as keeping their order of addition and access them through index. If we often need to search or delete elements, List<T> is not the right data structure. Use List<T>, when you have to add elements quickly and access them through index.

The way we declare a List is simple. As we learned from the Generics lesson, <T> actually indicated that we can use any type of data we want, because the method, structure, class, etc, doesn’t care what type of data we are sending to it. In our case, List<T> means that our List can store any kind of elements: int, string, float, etc. This is how we declare and initialize a List<T>:

List<int> list = new List<int>();

By replacing <T> with <int>, we told our List that we want to store elements of type integer. The procedure is the same for any other data type. We can even declare a class with methods and members, and then create a List of that classes type:

using System.Collections;

class Program
{
    static void Main()
    {
        //declare a new List of type custom class, declared below
        List<Test> myList = new List<Test>();

        //add a new instance of the custom class as element of our list
        myList.Add(new Test() { myInt = 5, myString = "some string" });

        //access a variable of the custom class element in our list
        int newInt = myList[0].myInt;

        //call the method inside our custom class stored in our list
        myList[0].MyMethod();
    }
}

//declare some custom class
class Test
{
    public int myInt;
    public string myString;

    public void MyMethod()
    {
        Console.WriteLine(myString);
    }
}

One thing to notice about the List is the fact that once you declare it of a certain type, you cannot add any other types to it. In other words, if you declare a list of type string, you can only add string variables to it, and no other type.

The most important methods of Lists are:

Add() – This appends a new element object to the end. We can keep adding elements to the collection until memory runs out. Example:

using System.Collections;

class Program
{
    static void Main()
    {
        List<int> list = new List<int>();
        list.Add(2);
        list.Add(3);
        list.Add(5);
        list.Add(7);
    }
}

AddRange() – for adding many elements at once, like adding an array to a List, we use the AddRange method. This can simplify code that combines collections. Here is how we use it:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> a = new List<int>();
        a.Add(1);
        a.Add(2);
        a.Add(5);
        a.Add(6);

        // Contains:
        // 1
        // 2
        // 5
        // 6

        int[] b = new int[3];
        b[0] = 7;
        b[1] = 6;
        b[2] = 7;

        a.AddRange(b);

        // Contains:
        // 1
        // 2
        // 5
        // 6
        // 7 [added]
        // 6 [added]
        // 7 [added]
        foreach (int i in a)
        {
            Console.WriteLine(i);
        }
    }
}

Clear() – You can call the instance method Clear() on your List. Example:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<bool> list = new List<bool>();
        list.Add(true);
        list.Add(false);
        list.Add(true);
        Console.WriteLine(list.Count); // 3

        list.Clear();
        Console.WriteLine(list.Count); // 0
    }
}

Sort(), Reverse() – these methods do exactly what their name says: they sort a List, or reverse the order of their elements. In case of sorting, for strings it orders alphabetically; for integers (or other numbers) it orders from lowest to highest. Example:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> list = new List<string>();
        list.Add("tuna");
        list.Add("velvetfish");
        list.Add("angler");

        // Sort fish alphabetically, in ascending order (A - Z)
        list.Sort();

        foreach (string value in list)
            Console.WriteLine(value);

        var reverse = list.Reverse();
        // Write contents of list to screen.
        foreach (string value in reverse)
            Console.WriteLine(value);
    }
}

Insert(), Remove(), RemoveAt() – methods used to add or remove elements into a List. RemoveAt() uses a numeric index to specify which element you want to remove. Example:

using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> list = new List<int>();
        for (int i = 0; i < 100000; i++)
        {
            // Insert before first element
            list.Insert(0, i); // SLOW
        }

        //clear list
        list.Clear();
        for (int i = 0; i < 100000; i++)
        {
            // Add to end
            list.Add(i); // FAST
        }

        //declare a new int array
        int[] b = new int[3];
        b[0] = 7;
        b[1] = 6;
        b[2] = 7;

        //insert the new array into the list, at position 1
        list.InsertRange(1, b);

        //remove speciffic element
        list.Remove(5);
        //remove at certain index
        list.RemoveAt(2);
    }
}

IndexOf() – This determines the element index of a certain value in the List collection. It searches for the first position (from the start) of the value. IndexOf has two overloads. It works in the same way as string’s IndexOf. It searches by value and returns the location. Example:

sing System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> primes = new List<int>(new int[] { 19, 23, 29 });

        int index = primes.IndexOf(23); // Exists.
        Console.WriteLine(index);

        index = primes.IndexOf(10); // Does not exist.
        Console.WriteLine(index);
    }
}

Contains(), Exists(), Find(). These methods all provide searching. They vary in arguments accepted. With Predicates, we influence what elements match. We haven’t learn about LinQ and predicates, but they are not the scope of this lesson. Example:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // Create List with three elements.
        var list1 = new List<string>();
        list1.Add("cat");
        list1.Add("dog");
        list1.Add("moth");

        // Search for this element.
        if (list1.Contains("dog"))
            Console.WriteLine("dog was found");

        // Search for this element in any string case.
        // ... This is the LINQ method with the same name.
        if (list1.Contains("MOTH", StringComparer.OrdinalIgnoreCase))
            Console.WriteLine("MOTH was found (insensitive)");

        // This element is not found.
        Console.WriteLine(list1.Contains("fish"));

        List<int> list2 = new List<int>();
        list2.Add(7);
        list2.Add(11);
        list2.Add(13);

        // See if any elements with values greater than 10 exist.
        bool exists = list2.Exists(element => element > 10);
        Console.WriteLine(exists);

        // Check for numbers less than 7.
        exists = list2.Exists(element => element < 7);
        Console.WriteLine(exists);

        List<int> list3 = new List<int>(new int[] { 19, 23, 29 });

        // Finds first element greater than 20
        int result = list3.Find(item => item > 20);

        Console.WriteLine(result);
    }
}

ToArray() – returns an array composed of the list’s elements. Example:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // List of cities we need to join.
        List<string> cities = new List<string>();
        cities.Add("New York");
        cities.Add("Mumbai");
        cities.Add("Berlin");
        cities.Add("Istanbul");

        // Join strings into one CSV (comma separated values) line.
        string line = string.Join(",", cities.ToArray());
        Console.WriteLine(line);
    }
}

Distinct() – removes duplicates from a list. Example:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // List with duplicate elements.
        List<int> list = new List<int>();
        list.Add(1);
        list.Add(2);
        list.Add(3);
        list.Add(3);
        list.Add(4);
        list.Add(4);
        list.Add(4);

        foreach (int value in list)
        {
            Console.WriteLine("Before: {0}", value);
        }

        // Get distinct elements and convert into a list again.
        List<int> distinct = list.Distinct().ToList();

        foreach (int value in distinct)
        {
            Console.WriteLine("After: {0}", value);
        }
    }
}

Equality() – Sometimes we need to test two Lists for equality, even when their elements are unordered. We can sort and then compare, or use a custom List equality method. Example:

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        List<Cube> cubes = new List<Cube>();

        cubes.Add(new Cube(8, 8, 4));
        cubes.Add(new Cube(8, 4, 8));
        cubes.Add(new Cube(8, 6, 4));

        if (cubes.Contains(new Cube(8, 6, 4))) 
            Console.WriteLine("An equal cube is already in the collection.");
        else 
            Console.WriteLine("Cube can be added.");
        //Outputs "An equal cube is already in the collection."
    }
}

public class Cube : IEquatable<Cube>
{
    public int Height { get; set; }
    public int Length { get; set; }
    public int Width { get; set; }

    public Cube(int h, int l, int w)
    {
        this.Height = h;
        this.Length = l;
        this.Width = w;
    }

    public bool Equals(Cube other)
    {
        if (this.Height == other.Height && this.Length == other.Length && this.Width == other.Width) 
            return true;
        else 
            return false;
    }
}

The most important properties of List are:

Capacity – We can use the Capacity property on List, or pass an integer to the constructor (which sets an initial capacity) to improve allocation performance.
Count – To get the number of elements, access the Count property. This is fast – just avoid the Count extension method. Count, on the List type, is equal to Length on arrays.