Fundamental Built-In Generic Classes

Introduction to the Collections Namespaces

The first public version of the .NET Framework was released as 1.1 in 2002. It contained a very impressive series of classes that could be used to create and manage collections. Most of the collection classes was created in the System.Collections namespace. The main goal was to provide all the routine operations performed on a list of items, whether a list of primitive values or a collection of composite objects. The flexibility of the new concept, as opposed to C++'s way of doing things, was the heavy use of interfaces. One of the classes introduced by the System.Collections namespaces is namedArrayList.

The 2.0 release of the .NET Framework saw the arrival of generic classes. The idea was to modernize the capabilities of existing collection classes. As a result, a new namespace was created and named System.Collections.Generics. Of course, to use a class from this namespace, make sure you qualify the name of its class or add the namespace in your using section:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        return 0;
    }
}

 A new equivalent version was created for most of the classes and interfaces of the System.Collections namespaces.

Introduction to the List Class

One of the classes introduced by the System.Collections.Generics namespace is named List. This is probably the most commonly used generic class of the .NET Framework. It is primarily the  System.Collections.Generics equivalent of the System.Collections's ArrayList. It allows you to create a list of any kind of value.

Like any normal (non-static) class, to use a List object, you must first declare a variable for it. As a reminder of how to use a generic class, the formula to declare the variable is:

List<type-name> variable-name = new List<type-name>();

You can also declare the variable using the var keyword:

var variable-name = new List<type-name>();

You can also use the dynamic keyword:

dynamic variable-name = new List<type-name>();

These techniques use the default constructor of the List class. If the list is made of values of primitive types, put that value in the type-name placeholder. Here are examples of List variables:

List<int> numbers = new List<int>();
var symbols = new List<char>();
dynamic names = new List<string>();

If the list is made of objects, make sure you specify it. You can use one of the existing classes of the .NET Framework. Here are examples:

using System.Collections.Generic;

List<EventArgs> eventArguments = new List<EventArgs>();
var enumerations = new List<Enum>();
dynamic exceptions = new List<Exception>();

Or you can create your own class. In both cases, the class must not be static.

Introduction to Using a List

Adding an Item to a List

The List class primarily supports all the necessary operations of a list. To allow you to add an item, the class is equipped with a method named Add. Its syntax is:

public void Add(T item)

To use it, simply pass the desired item to the method. If the value is a primitive type and if you want to pass a constant value, you must follow the rules of values of that type:

Here are examples:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        List<int> numbers = new List<int>();
        numbers.Add(248);
        
        var symbols = new List<char>();
        symbols.Add('%');

        dynamic names = new List<string>();
        names.Add("James");

        return 0;
    }
}

Otherwise, you can first declare a variable for the value and pass the name of the variable to the List.Add() method.

If you are using a class, you must follow the rules of classes:

You can use the List.Add() method to add an item or to add many items one at a time. As an alternative, to let you add many items at the same time, the List class provides the AddRange() method.

Returning a Generic List From a Method

You can create a list in a method and return it. When defining the method, specify its return value as List<>. Inside the <> operator, write the type of value. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    static List<int> GetNumbers()
    {
        
    }
}

You can then define the method however you like, before exiting, you must make sure you return a List<> object. To use the list produced by the method, you can assign its return to local variable. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    static List<int> GetNumbers()
    {
        List<int> nbrs = new List<int>();

        nbrs.Add(84);
        nbrs.Add(27407);
        nbrs.Add(5948);
        nbrs.Add(7);
        nbrs.Add(927482);

        return nbrs;
    }

    public static int Main()
    {
        List<int> numbers = new List<int>();
        numbers = GetNumbers();

        return 0;
    }
}

Passing a Generic List as Argument

You can use a list either in a local method where it is created or you can pass it to be processed by another method. You pass it the same way you would any value, using List<TypeOfValue> ArgumentName. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    static void ShowNumbers(List<int> numbers)
    {
    }
}

In the method, you can use the argument any way you like.

The Number of Items in a List

To keep track of the number of items in a collection, the List class is equipped with a read-only property named Count:

public int Count { get; }

Here are examples of accessing it:

public class Exercise
{
    public static int Main()
    {
        List<Employee> contractors = new List<Employee>();

        Employee empl = new Employee(397947, "David", "Redson", 18.75);
        contractors.Add(empl);
        empl = new Employee(840004, "Simao");
        contractors.Add(empl);
        contractors.Add(new Employee());
        
        var seasonals = new List<Employee>();
        seasonals.Add(new Employee(848024, "Alima", "Bieyrou", 14.05));
        seasonals.Add(new Employee(fName : "Robert", lName : "Nants"));

        dynamic identifications = new List<Employee>();
        identifications.Add(new Employee(222222));

        Console.WriteLine("This company has {0} contractors, {1} seasonal " +
                          "employees, and {2} other type.", contractors.Count,
                          seasonals.Count, identifications.Count);
                          
        return 0;
    }
}

This would produce:

This company has 3 contractors, 2 seasonal employees, and 1 other type.
Press any key to continue . . .

The Capacity of a List

When you declare a List variable, the compiler reserves a certain area and amount of memory for it. If you want, you can tell the compiler how much initial memory to reserve. To support this, the List class is equipped with a property named Capacity:

public int Capacity { get; set; }

To specify the initial capacity when declaring the List variable, you can use the following constructor:

public List(int capacity);

On the other hand, to get the capacity of a List variable, get the variable of its Capacity.

Accessing an Item

To let you access an item, the List class uses an indexed property named Item. This allows you to access its items using the [] operator. Here are examples:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var name = new List<char>();
        name.Add('A');
        name.Add('p');
        name.Add('l');
        name.Add('e');

        Console.Write("{0}", name[0]);
        Console.Write("{0}", name[1]);
        Console.Write("{0}", name[1]);
        Console.Write("{0}", name[2]);
        Console.Write("{0}", name[3]);
        Console.WriteLine();

        return 0;
    }
}

This would produce:

Apple
Press any key to continue . . .

You can also use a for loop to access each item of the list. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var internetCode = new List<char>();
        internetCode.Add('c');
        internetCode.Add('o');
        internetCode.Add('m');

        Console.Write("http://www.kamerun.");
        for(int i = 0; i < internetCode.Count; i++)
            Console.Write("{0}", internetCode[i]);

        Console.WriteLine();
        return 0;
    }
}

This would produce:

http://www.kamerun.com
Press any key to continue . . .

If the list is made of objects of a class, to access an item, apply the square brackets to the variable, followed by a period, and followed by the desired member of the class. Here are examples:

public class Exercise
{
    public static int Main()
    {
        List<Employee> contractors = new List<Employee>();

        Employee empl = new Employee(397947, "David", "Redson", 18.75);
        contractors.Add(empl);
        contractors.Add(new Employee(174966, "Alfred", "Swanson", 12.94));
        empl = new Employee(840004, "Simao");
        contractors.Add(empl);
        contractors.Add(new Employee(848024, "Alima", "Bieyrou", 14.05));
        contractors.Add(new Employee(number: 397462,
        			     fName : "Robert", 
        			     lName : "Nants"));

        dynamic identifications = new List<Employee>();
        identifications.Add(new Employee(222222));

        for (int i = 0; i < contractors.Count; i++)
        {
            Console.WriteLine("Employee #:    {0}\nFirst Name:    {1}\n" +
                              "Last Name:     {2}\n" +
                              "Hourly Salary: {3:F}",
                              contractors[i].EmployeeNumber,
                              contractors[i].FirstName,
                              contractors[i].LastName,
                              contractors[i].HourlySalary);
            Console.WriteLine("-----------------------");
        }
                          
        return 0;
    }
}

This would produce:

Employee #:    397947
First Name:    David
Last Name:     Redson
Hourly Salary: 18.75
-----------------------
Employee #:    174966
First Name:    Alfred
Last Name:     Swanson
Hourly Salary: 12.94
-----------------------
Employee #:    840004
First Name:    Simao
Last Name:     Doe
Hourly Salary: 12.00
-----------------------
Employee #:    848024
First Name:    Alima
Last Name:     Bieyrou
Hourly Salary: 14.05
-----------------------
Employee #:    397462
First Name:    Robert
Last Name:     Nants
Hourly Salary: 12.00
-----------------------
Press any key to continue . . .

Enumerating a List

 

Introduction

In previous sections, we saw that you can use a for loop to scan a list of items. To support the foreach operator, the List class is equipped with a method named GetEnumerator. Its syntax is:

public List<(Of <(<'T>)>)>..::..Enumerator GetEnumerator();

Normally, you don't need to know anything about this method. You use foreach the same was we saw for arrays. Here is an example:

public class Exercise
{
    public static int Main()
    {
        List<Employee> employees = new List<Employee>();

        Employee empl = new Employee(397947, "David", "Redson", 18.75);
        employees.Add(empl);
        employees.Add(new Employee(174966, "Alfred", "Swanson", 12.94));
        employees.Add(new Employee(848024, "Alima", "Bieyrou", 14.05));
        employees.Add(new Employee(number: 397462, fName: "Robert",
                                     lName: "Nants", salary: 22.15));

        foreach (Employee staffMember in employees)
        {
            Console.WriteLine("================================");
            Console.WriteLine("Employee Record");
            Console.WriteLine("--------------------------------");
            Console.WriteLine("Employee #:    {0}", staffMember.EmployeeNumber);
            Console.WriteLine("First Name:    {0}", staffMember.FirstName);
            Console.WriteLine("Last Name:     {0}", staffMember.LastName);
            Console.WriteLine("Hourly Salary: {0}", staffMember.HourlySalary);
        }

        return 0;
    }
}

For Each Method Call

The List class provides its own method that performs the operation of foreach. Its name is ForEach and its syntax is:

public void ForEach(Action<T> action);

This method expects a function that defines what to do every time the compiler visits a members of the list. You do this by creating a method to do something on each member of the List<> collection and then pass that method to ForEach(). Here is an example:

public class Exercise
{
    public void ShowEmployee(Employee empl)
    {
        Console.WriteLine("================================");
        Console.WriteLine("Employee Record");
        Console.WriteLine("--------------------------------");
        Console.WriteLine("Employee #:    {0}", empl.EmployeeNumber);
        Console.WriteLine("First Name:    {0}", empl.FirstName);
        Console.WriteLine("Last Name:     {0}", empl.LastName);
        Console.WriteLine("Hourly Salary: {0}", empl.HourlySalary);
    }

    public static int Main()
    {
        Exercise exo = new Exercise();
        List<Employee> employees = new List<Employee>();

        Employee empl = new Employee(397947, "David", "Redson", 18.75);
        employees.Add(empl);
        employees.Add(new Employee(174966, "Alfred", "Swanson", 12.94));
        employees.Add(new Employee(848024, "Alima", "Bieyrou", 14.05));
        employees.Add(new Employee(number: 397462, fName: "Robert",
                                   lName: "Nants", salary: 22.15));

        employees.ForEach(exo.ShowEmployee);
        
        return 0;
    }
}

Looking for an Item

  

Introduction

The List class provides various means of finding out whether an item exists in a list. One of the methods you can use is named Contains. Its syntax is:

public bool Contains(T item);

This methods takes as argument the item to look for. If that item exists in the list, the method returns true. Otherwise, it returns false. This method is easy to use on a list that contains value of primitive types. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var connection = new List<char>();
        connection.Add('c');
        connection.Add('o');
        connection.Add('n');
        connection.Add('n');
        connection.Add('e');
        connection.Add('c');
        connection.Add('t');
        connection.Add('i');
        connection.Add('o');
        connection.Add('n');

        for (int i = 0; i < connection.Count; i++)
            Console.Write("{0}", connection[i]);
        Console.WriteLine();

        if (connection.Contains('e'))
            Console.WriteLine("The list contains 'e'");
        else
            Console.WriteLine("There is no 'e' in the list");

        if (connection.Contains('g'))
            Console.WriteLine("The list contains 'g'");
        else
            Console.WriteLine("There is no 'g' in the list");

        return 0;
    }
}

This would produce:

connection
The list contains 'e'
There is no 'g' in the list
Press any key to continue . . .

This works because each structure of a primitive type is equipped to compare two of its values. The comparison would not work directly if the list is made of values of your own class. Consider the following:

using System.Collections.Generic;

public class Employee
{
    public long EmployeeNumber { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public double HourlySalary { get; set; }

    public Employee(long number = 0, string fName = "John",
                    string lName = "Doe", double salary = 12.05D)
    {
        EmployeeNumber = number;
        FirstName = fName;
        LastName = lName;
        HourlySalary = salary;
    }

    public override string ToString()
    {
        base.ToString();

        return string.Format("================================\n" +
                             "Employee Record\n" +
                             "--------------------------------\n" +
                             "Employee #:    {0}\nFirst Name:    {1}\n" +
                             "Last Name:     {2}\nHourly Salary: {3}",
                             EmployeeNumber, FirstName,
                             LastName, HourlySalary);
    }
}

public class Exercise
{
    public static int Main()
    {
        List<Employee> employees = new List<Employee>();

        Employee empl = new Employee(397947, "David", "Redson", 18.75);
        employees.Add(empl);
        employees.Add(new Employee(174966, "Alfred", "Swanson", 12.94));
        employees.Add(new Employee(848024, "Alima", "Bieyrou", 14.05));
        employees.Add(new Employee(number: 397462, fName: "Robert",
                                     lName: "Nants", salary: 22.15));

        Employee member = new Employee(174966, "Alfred", "Swanson", 12.94);

        bool exists = employees.Contains(member);

        if (exists == true)
            Console.WriteLine("The list contains the employee");
        else
            Console.WriteLine("No record of that employee was found");

        return 0;
    }
}

This would produce:

No record of that employee was found
Press any key to continue . . .

Notice that the compiler was not able to find the item even though it actually exists in the list. To make this method work on your class, you must override the Equals() method. Here is an example:

using System.Collections.Generic;

public class Employee
{
    public long EmployeeNumber { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public double HourlySalary { get; set; }

    public Employee(long number = 0, string fName = "John",
                    string lName = "Doe", double salary = 12.05D)
    {
        EmployeeNumber = number;
        FirstName = fName;
        LastName = lName;
        HourlySalary = salary;
    }

    public override bool Equals(object obj)
    {
        Employee e = (Employee)obj;

        if ((e.EmployeeNumber == this.EmployeeNumber) &&
            (e.FirstName == this.FirstName) &&
            (e.LastName == this.LastName) &&
            (e.HourlySalary == this.HourlySalary))
            return true;
        else
            return false;
    }

    public override string ToString()
    {
        base.ToString();

        return string.Format("================================\n" +
                             "Employee Record\n" +
                             "--------------------------------\n" +
                             "Employee #:    {0}\nFirst Name:    {1}\n" +
                             "Last Name:     {2}\nHourly Salary: {3}",
                             EmployeeNumber, FirstName,
                             LastName, HourlySalary);
    }
}

public class Exercise
{
    public static int Main()
    {
        . . . No Change

        return 0;
    }
}

This time, the program would produce:

The list contains the employee
Press any key to continue . . .

Getting the Index of Item

You can ask the compiler to look for an item in the list and, if it finds it, to give you the index of that item. To make this request, use the IndexOf() method. It is overloaded with three versions. One of them uses the following syntax:

public int IndexOf(T item);

When calling this method, if the list is made of values of primitive types, pass the value as argument. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var connection = new List<char>();
        
        connection.Add('c');
        connection.Add('o');
        connection.Add('n');
        connection.Add('n');
        connection.Add('e');
        connection.Add('c');
        connection.Add('t');
        connection.Add('i');
        connection.Add('o');
        connection.Add('n');

        for (int i = 0; i < connection.Count; i++)
            Console.Write("{0}", connection[i]);
        Console.WriteLine();

        Console.WriteLine("The index of 'n' is {0}", connection.IndexOf('n'));

        return 0;
    }
}

This would produce:

connection
The index of 'n' is 2
Press any key to continue . . .

As mentioned for the Contains() method, when you call the IndexOf() method, the compiler compares each member of the collection with the value passed as argument. This works fine on value of primitive types because they have built-in comparison in their structures. If you want this to work on a class you created, you must override the Equals() method.

If you call the above version of the IndexOf() method, the compiler would look for the item in the entire list starting from the beginning, the 0-index. If you want, you can ask the compiler to start looking at a specific position. To do this, use the following version of the IndexOf() method:

public int IndexOf(T item, int index);

This time, besides the item, pass an index as the second argument. The compiler would look for the item starting at that index to the end.

When you use the IndexOf() method, the compiler would look for the item starting from the left to the right. If you prefer to look for the item from the end of the list, you can use the LastIndexOf() method. It is overloaded with three versions. One of them uses a syntax as:

public int LastIndexOf(T item);

Here is an example of calling this method:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var connection = new List<char>();
        
        connection.Add('c');
        connection.Add('o');
        connection.Add('n');
        connection.Add('n');
        connection.Add('e');
        connection.Add('c');
        connection.Add('t');
        connection.Add('i');
        connection.Add('o');
        connection.Add('n');

        for (int i = 0; i < connection.Count; i++)
            Console.Write("{0}", connection[i]);
        Console.WriteLine();

        Console.WriteLine("The index of 'n' from the end to the beginning is {0}",
                          connection.LastIndexOf('n'));

        return 0;
    }
}

This would produce:

connection
The index of 'n' from the end to the beginning is 9
Press any key to continue . . .

If you prefer to look for the item starting at a certain index from the end, use the following syntax:

public int LastIndexOf(T item, int index);

Deleting Items

 

Deleting an Item Using its Index

There are various ways you can remove an item from a list. To let you delete an item based on its index, you can call the RemoveAt() method. Its syntax is:

public void RemoveAt(int index);

When calling this method, pass the index of the undesired item. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var internetCode = new List<char>();
        internetCode.Add('c');
        internetCode.Add('o');
        internetCode.Add('m');

        Console.Write("http://www.kamerun.");
        for(int i = 0; i < internetCode.Count; i++)
            Console.Write("{0}", internetCode[i]);
        Console.WriteLine();

        internetCode.RemoveAt(1);

        Console.Write("http://www.kamerun.");
        for (int i = 0; i < internetCode.Count; i++)
            Console.Write("{0}", internetCode[i]);
        Console.WriteLine();

        return 0;
    }
}

This would produce:

http://www.kamerun.com
http://www.kamerun.cm
Press any key to continue . . .

As you can see, the RemoveAt() method is the easy way to delete an item from a list if you know its index. Another way you can proceed would consist of finding out first if the item exists in the list, get its index, and then pass that index.

Deleting a Range of Items

Still using an index, but instead of deleting just one, you can remove a range of value from a list. To support this, the List<> class provides the RemoveRange() method. Its syntax is:

public void RemoveRange(int index, int count);

The first item is the index from where to start deleting items. The second argument specifies the number of items to delete from the index to the end of the list.

Deleting a Known Item

Instead of locating an item based on its index, you can ask the List class to look for it. To support this, it is equipped with a method named Remove. Its syntax is:

public bool Remove(T item);

In this case, you pass a definition of the item to the method. Here is an example:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var internetCode = new List<char>();
        internetCode.Add('c');
        internetCode.Add('o');
        internetCode.Add('m');

        Console.Write("http://www.kamerun.");
        for(int i = 0; i < internetCode.Count; i++)
            Console.Write("{0}", internetCode[i]);
        Console.WriteLine();

        internetCode.Remove('o');

        Console.Write("http://www.kamerun.");
        for (int i = 0; i < internetCode.Count; i++)
            Console.Write("{0}", internetCode[i]);
        Console.WriteLine();

        return 0;
    }
}

When you call the List.Remove() method, the compiler would look for the item in the collection:

Notice that the list contains three Ns but only the first was removed.

If the item is based on a class, you must (it is your responsibility, the List class it not equipped to) provide a way to identify an item. This is usually done by overriding the Equals() method.

Clearing the List

To delete all items from a list, call the Clear() method. Its syntax is:

public void Clear();

Other Operations on a List

 

Creating a Sub-List

If you have an existing list, you can use a range of indices from it to retrieve a new list. To support this operation, the List class provides the GetRange() method whose syntax is:

public List<T> GetRange(int index, int count);

The first argument of this method is the start point of the range. The second argument is the number of items from the index to include in the new list. Here are examples of calling this method:

using System.Collections.Generic;

public class Exercise
{
    public static int Main()
    {
        var connection = new List<char>();
        
        connection.Add('c');
        connection.Add('o');
        connection.Add('n');
        connection.Add('n');
        connection.Add('e');
        connection.Add('c');
        connection.Add('t');
        connection.Add('i');
        connection.Add('o');
        connection.Add('n');

        for (int i = 0; i < connection.Count; i++)
            Console.Write("{0}", connection[i]);
        Console.WriteLine();

        List<char> connect = connection.GetRange(0, 7);

        for (int i = 0; i < connect.Count; i++)
            Console.Write("{0}", connect[i]);
        Console.WriteLine();

        List<string> person = new List<string>();
        person.Add("Paul");
        person.Add("Martin");
        person.Add("Souffrance");
        person.Add("Eto");
        person.Add("Zambo");

        for (int i = 0; i < person.Count; i++)
            Console.Write("{0} ", person[i]);
        Console.WriteLine();

        List<string> pers = person.GetRange(1, 2);

        for (int i = 0; i < pers.Count; i++)
            Console.Write("{0} ", pers[i]);
        Console.WriteLine();

        return 0;
    }
}

This would produce:

connection
connect
Paul Martin Souffrance Eto Zambo
Martin Souffrance
Press any key to continue . . .

In the same way, you can create a sub-list of objects from an existing collection.

Converting a List Into an Array

To convert a list into an array, you can call the ToArray() method of the List<> class. Its syntax is:

public T[] ToArray();

Here is an example of calling this method:

public class Exercise
{
    public static int Main()
    {
        List<Employee> contractors = new List<Employee>();

        Employee empl = new Employee(397947, "David", "Redson", 18.75);
        contractors.Add(empl);
        contractors.Add(new Employee(174966, "Alfred", "Swanson", 12.94));
        contractors.Add(new Employee(405809, "Amie", "Tripp", 16.55));
        contractors.Add(new Employee(294815, "Theodore", "Ludlum", 8.05));
        contractors.Add(new Employee(848024, "Alima", "Bieyrou", 14.05));
        contractors.Add(new Employee(number: 397462, fName: "Robert",
                                     lName: "Nants", salary : 22.15));

        Employee[] employees = contractors.ToArray();

        foreach (Employee staff in employees)
            Console.WriteLine(staff);

        return 0;
    }
}

Fundamental Built-In Generic Interfaces

 

Introduction

Although you probably already know how to create collection from scratch, the .NET Framework provides an impression library of interfaces. Although you can still decide to create your own collection class from nothing, it is recommended that you implement one of the built-in generic collection interfaces.

Introduction to the IEnumerable Interface

From our knowledge of collection classes, we know that one of the most common operations consists of visiting each member of a list. This operation is also referred to as iterating through a collection. To support this operation, the .NET Framework provides an interface named IEnumerable. Both the System.Collections and the System.Collections.Generic namespaces have each a version of this interface. The System.Collections.IEnumerable interface starts as follows:

public interface IEnumerable

The System.Collections.Generics.IEnumerable interface starts as follows:

public interface IEnumerable<out T> : IEnumerable

Introduction to the ICollection Generic Interface

If you want to create a generic collection class that follows the .NET standards, you must implement an interface named ICollection. The ICollection<> interface is a member of the System.Collections.Generic namespace and starts as follows:

public interface ICollection<T> : IEnumerable<T>, IEnumerable

Based on this, to start a collection class, implement the System.Collections.ICollection<> interface. Here is an example:

using System.Collections.Generic;

class Collection<T> : ICollection<T>
{
}

Introduction to the IList Interface

To help you create a generic collection class with more functionality, the .NET Framework provides an interface named IList. The IList<> interface is a member of the System.Collections.Generic namespace. That interface starts as follows:

public interface IList<T> : ICollection<T>,
			    IEnumerable<T>, 
			    IEnumerable

To use it, implement it from your collection class. Here is an example:

using System.Collections.Generic;

public class Collection<T> : IList<T>
{
}

As seen above, the IList<> interface is derived from both the ICollection and the generic ICollection<> interfaces. This means that you must implement their members.

If you start a class that implements at least one interface as done above, if you try executing the application, you would receive an error because you must first implment all the members of the interfaces. One way you can avoid the error is to create default code for all members, even if that code doesn't do anything. If you are using Microsoft Visual Studio, you can ask it to generat the default code of the interface(s) for you. To do this, after writing code like the above, right-click the name of the interface, position the mouse on Implement Interface, and click Implement Interface:

Interface

As an alternative, click the name of the interface. A button would appear under it. Position the mouse on that button and click it:

Interface

The click the Implement Interface option. In both cases, the studio would generate the default code of the members of the interface(s) for you.

Fundamentals of Creating a Collection Class

 

Introduction

You can store the actual items of your collection class in an array. To start, you can create the array in the body of the class and initialize it in a constructor. Here is an example:

public class Collection<T> : IList<T>
{
    private T[] items;

    public Collection()
    {
        items = new T[10];
    }
}

The Number of Items in a Collection

To help you keep track of the number of items in the collection class, the ICollection<T> interface is equipped with a read-only property named Count:

int Count { get; }

 In your class, you must implement this property. Here is an example:

using System.Collections.Generic;

public class Collection<T> : IList<T>
{
    private int size;

    public Collection()
    {
        size = 0;
    }

    public virtual int Count
    {
        get { return size; }
    }
}

Copying a Collection

The ICollection<> interface also allows its implementer to copy some of its items to an array. To provide this functionality, the interface is equipped with a method named CopyTo, which you must implement. The syntax of this method is:

void CopyTo(T[] array, int arrayIndex);

This method takes two arguments. The first argument is the array that will receive the items. The second argument is the position of the item from where the copying operation will begin. Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    public Collection()
    {
        size = 0;
        items = new T[10];
    }

    public virtual int Count
    {
        get { return size; }
    }

    public void CopyTo(T[] array, int index)
    {
        T[] values = new T[size];

        for (int i = 0; i < size; i++)
            values[i] = items[i];

        array = values;
    }
}

Enumerating a Collection

As seen in our introduction, the ICollection<> interface inherits from both the IEnumerable<> generic interface and the IEnumerable general interface. The IEnumerable<> generic interface is equipped with only one method that is named GetEnumerator. Its syntax is:

IEnumerator<T> GetEnumerator();

The IEnumerable generic interface is equipped with the following method:

IEnumerator GetEnumerator();

Consequently, you must implement both methods in your generic collection class. Here are examples:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    public Collection()
    {
        size = 0;
        items = new T[10];
    }

    public virtual int Count
    {
        get { return size; }
    }

    public void CopyTo(T[] array, int index)
    {
        T[] values = new T[size];

        for (int i = 0; i < size; i++)
            values[i] = items[i];

        array = values;
    }

    public IEnumerator<T> GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }
}

A Read-Only Collection

Most collections are made to receive new values. If you want, you can create a list that cannot receive new values. To support this, the ICollection<> interface is equipped with a Boolean property named IsReadOnly:

bool IsReadOnly { get; }

The IList<> interface inherits the IsReadOnly property from its parent: ICollection<>. Here is an example of implementing the IsReadOnly property for the System.Collections.IList interface:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    public Collection()
    {
        size = 0;
        items = new T[10];
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        T[] values = new T[size];

        for (int i = 0; i < size; i++)
            values[i] = items[i];

        array = values;
    }

    public int Count
    {
        get { return size; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }
}

Adding an Item

The primary operation to perform on a list is to populate it with at least one value. To support this, the ICollection<> generic interface is equipped with a method named Add, which the IList<> generic interface inherits. Its syntax is:

void Add(T item);

This method takes one argument as the value to add to the collection. If your collection is an array, you can first check that there is still enough room in the list to add a new item. In reality, this is never an issue with the IList<> interface:

In Lesson 4, we saw that the Add() method can be defined as follows::

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    public void Add(T item)
    {
        this.items[this.size] = item;
        this.size++;
    }
}

By default, an array has a fixed size. If you try adding an item in a position higher than the maximum number of items, the compiler would throw an IndexOutOfRangeException. Fortunately, the Array class is equipped with a method named Resize. This allows you to increase the size of an array when you judge it necessary. As a consequence, you can have an array as big as possible. Based on this, you can implement the Add() method as follows:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    private void IncreaseIfNecessary()
    {
        if (size >= items.Length)
            Array.Resize<T>(ref items, items.Length + 5);
    }

    public void Add(T value)
    {
        // Check whether there is still room in the array.
        // If there is not enough room, then increase the capacity
        IncreaseIfNecessary();

        // Add the item at the end
        this.items[this.size] = value;
        // Increase the current number of items
        this.size++;
    }
}

Once the collection class has an Add() method, you can use it to add new items to the collection. Here are examples:

public class Exercise
{
    public static int Main()
    {
        Collection<double> numbers = new Collection<double>();

        numbers.Add(14.88);
        numbers.Add(284.05);
        numbers.Add(8.495);
        numbers.Add(6626.14);
        numbers.Add(3.006);

        return 0;
    }
}

this Item of a Collection

While using a list, various operations require that you know the object you are currently accessing. To provide this operation, the IList<> interface is equipped with an indexed property named Item that you must implement. The Item property of the System.Collection.Generic.IList interface is declared as follows:

T this[int index] { get; set; }

Here is an example of implementing the indexed property of the IList<> interface:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .

    // The index property can be used to add an item to a collection,
    // or to retrieve an item from the collection
    public T this[int index]
    {
        get
        {
            return this.items[index];
        }
        set
        {
            this.items[index] = value;
        }
    }
}

After creating this property, you can then access an item using its index and applying the [] operator on its instance. If you implement it right, this property can perform many types of operations:

Introduction to the Items of a Collection

Inserting an Item

When you call the Add() method, it adds the new value to the end of the list. Sometimes, you will want the new value to be inserted somewhere inside the list. To support this operation, the IList<> interface provide a method named Insert. Its method is:

void Insert(int index, T value);

This method takes two arguments. The second argument is the value that will be inserted into the list. The argument must hold a valid value:

The System.Collections.Generic.IList.Insert() method can be implemented as follows:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    private void CheckAndIncreaseIfNecessary()
    {
        if (size >= items.Length)
            Array.Resize<T>(ref items, items.Length + 5);
    }

    public void Add(T value)
    {
        // Check whether there is still room in the array.
        // If there is not enough room, then increase the capacity
        CheckAndIncreaseIfNecessary();

        // Add the item at the end
        this.items[this.size] = value;
        // Increase the current number of items
        this.size++;
    }

    public void Insert(int index, T value)
    {
        // If the index is the same as the current number of items
        // then call Add() and proceed as if we want to add a new item
        if (index >= size)
        {
            Add(value);
            return;
        }

        // If the index is positive but less than the current size,
        // then you need to insert the item inside the collection.
        if ((index >= 0) && (index < size))
        {
            // Firs, push each item one position up to create
            // an empty space
            for (int i = (size - 1); i > index - 1; i--)
                items[i + 1] = items[i];

            // Then put the new item in the indicated position
            items[index] = value;
            // Since the new item has been added, increase the 
            // current number of items
            size++;
        }
    }
}

public class Exercise
{
    public static int Main()
    {
        Collection<double> numbers = new Collection<double>();

        numbers.Add(14.88);
        numbers.Add(284.05);
        numbers.Add(8.495);
        numbers.Add(6626.14);
        numbers.Add(3.006);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("---------------");

        numbers.Insert(2, 50.50505);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);

        return 0;
    }
}

This would produce:

Number: 14.88
Number: 284.05
Number: 8.495
Number: 6626.14
Number: 3.006
---------------
Number: 14.88
Number: 284.05
Number: 50.50505
Number: 8.495
Number: 6626.14
Number: 3.006
Press any key to continue . . .

Based on our implementation of the IList<>.Insert() method:

Checking Whether the Collection Contains an Item

One of the routine operations you can perform on a list is to find out whether it contains a certain value. To assist you with this operation, the IList<> interface is equipped with a method named Contains. Its syntax is:

bool Contains(T item);

This method takes as argument the value to look for. If the value is found in the collection, the method returns true. If no value is found in the collection, this method returns false.

Here is an example of implementing this method:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    public bool Contains(T value)
    {
        for (int i = 0; i < Count; i++)
            if (items[i].Equals(value))
                return true;
        return false;
    }
}

public class Exercise
{
    public static int Main()
    {
        Collection<int> numbers = new Collection<int>();

        numbers.Add(14);
        numbers.Add(88);
        numbers.Add(284);
        numbers.Add(8);
        numbers.Add(495);
        numbers.Add(6626);
        numbers.Add(306);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("----------------------------------");
        
        if( numbers.Contains(495) )
            Console.WriteLine("The list contains 495");
        else
            Console.WriteLine("The list doesn't contain 495");

        if( numbers.Contains(12095) )
            Console.WriteLine("The list contains 12095");
        else
            Console.WriteLine("The list doesn't contain 12095");

        return 0;
    }
}

This would produce:

Number: 14
Number: 88
Number: 284
Number: 8
Number: 495
Number: 6626
Number: 306
----------------------------------
The list contains 495
The list doesn't contain 12095
Press any key to continue . . .

If you want to use your own class as the items of the collectionm, you should (must) override the Equals() method on that class.

Getting the Index of an Item

The Contains() method is used to check whether a particular value (already) exists in the collection. If you know that a certain item exists but you don't know its index inside the list, the IList<> interface can assist you through a method named IndexOf. Its syntax is:

int IndexOf(T item);

This method takes as argument the value to look for in the list. If the value is found in the collection, the method returns its index. If there is no value defined like that, the method returns -1. Here is an example of implementing this method:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    public int IndexOf(T value)
    {
        for (int i = 0; i < Count; i++)
            if (items[i].Equals(value))
                return i;
        return -1;
    }
}

public class Exercise
{
    public static int Main()
    {
        Collection<int> numbers = new Collection<int>();

        numbers.Add(14);
        numbers.Add(88);
        numbers.Add(284);
        numbers.Add(8);
        numbers.Add(495);
        numbers.Add(6626);
        numbers.Add(306);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("----------------------------------");
        
        if( numbers.Contains(495) )
            Console.WriteLine("The index of 495 is {0}.", numbers.IndexOf(495));
        else
            Console.WriteLine("The list doesn't contain 495");

        if (numbers.Contains(12095))
            Console.WriteLine("The index of 495 is {0}.", numbers.IndexOf(12095));
        else
            Console.WriteLine("The list doesn't contain 12095");

        return 0;
    }
}

This would produce:

Number: 14
Number: 88
Number: 284
Number: 8
Number: 495
Number: 6626
Number: 306
----------------------------------
The index of 495 is 4.
The list doesn't contain 12095
Press any key to continue . . .

Once again, this method calls the Equals() method of the objects that make up the collection. In most cases, you should make sure you override the Equals() method in the class that T represents.

Deleting Items

Deleting a Value by its Index

If a value is not necessary in your collection, you can delete it. Probably the simplest way to delete a value is to specify its position in the list. To support this operation, the System.Collections.Generic.IList interface is equipped with a method named RemoveAt. The syntax is:

void RemoveAt(int index);

This method takes as argument the index of the value to be removed. If the index is valid, the method removes it. If the index is not valid, the compiler will throw and ArgumentOutOfRangeException. Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // This method is used to delete an item based on its position
    public void RemoveAt(int index)
    {
        // First check that the user provided a positive index that
        // is lower than the current total number of items
        if ((index >= 0) && (index < size))
        {
            // If so, starting at that index, get the item ahead of
            // each position and assign it to the current item
            for (int i = index; i < size - 1; i++)
                items[i] = items[i + 1];

            // Since the last item is not useful anymore,
            // decrease the number of items
            size--;
        }
    }
}

public class Exercise
{
    public static int Main()
    {
        Collection<int> numbers = new Collection<int>();

        numbers.Add(14);
        numbers.Add(88);
        numbers.Add(284);
        numbers.Add(8);
        numbers.Add(495);
        numbers.Add(6626);
        numbers.Add(306);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("----------------------------------");

        numbers.RemoveAt(2);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("----------------------------------");

        return 0;
    }
}

This would produce:

Number: 14
Number: 88
Number: 284
Number: 8
Number: 495
Number: 6626
Number: 306
----------------------------------
Number: 14
Number: 88
Number: 8
Number: 495
Number: 6626
Number: 306
----------------------------------
Press any key to continue . . .

If the item cannot be deleted for another reason, the compiler would throw an NotSupportedException.

Deleting an Item by its Value

The problem with deleting a value based on its index is that, if you are not sure, you could delete the wrong value. An alternative is to first precisely define the value you want to get rid of, and then hand the value itself to the compiler that would remove it. To support this approach, the ICollection<> interface is equipped with a method named Remove(). Its syntax is:

bool Remove(T item);

This method takes as argument the value to be deleted. This means that the compiler will first look for the value in the list. If it finds that value, it removes it. If there is no value like that, nothing happens. Here is an example of implementing this method:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // This method is used to delete an item
    public bool Remove(T value)
    {
        // First try to get the index of the item to find out if it exists
        int index = IndexOf(value);
        
        // If the item was found ...
        if (index >= 0)
        {
            // ... delete it, using its index
            RemoveAt(index);
            // Since the item has been removed, return true
            return true;
        }

        // If the item was not removed (for any reason), return false
        return false;
    }
}

public class Exercise
{
    public static int Main()
    {
        Collection<int> numbers = new Collection<int>();

        numbers.Add(14);
        numbers.Add(88);
        numbers.Add(284);
        numbers.Add(8);
        numbers.Add(495);
        numbers.Add(6626);
        numbers.Add(306);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("----------------------------------");

        numbers.Remove(495);

        for (int i = 0; i < numbers.Count; i++)
            Console.WriteLine("Number: {0}", numbers[i]);
        Console.WriteLine("----------------------------------");

        return 0;
    }
}

This would produce:

Number: 14
Number: 88
Number: 284
Number: 8
Number: 495
Number: 6626
Number: 306
----------------------------------
Number: 14
Number: 88
Number: 284
Number: 8
Number: 6626
Number: 306
----------------------------------
Press any key to continue . . .

Clearing a Collection

To remove all values from a list at once, you can implement the Clear() method of the IList<> interface. Its syntax is:

void Clear();

Here is an example of implementing it:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    public Collection()
    {
        size = 0;
        items = new T[10];
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        T[] values = new T[size];

        for (int i = 0; i < size; i++)
            values[i] = items[i];

        array = values;
    }

    public int Count
    {
        get { return size; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    private void CheckAndIncreaseIfNecessary()
    {
        if (size >= items.Length)
            Array.Resize<T>(ref items, items.Length + 5);
    }

    // The index property can be used to add an item to a collection,
    // or to retrieve an item from the collection
    public T this[int index]
    {
        get
        {
            return this.items[index];
        }
        set
        {
            this.items[index] = value;
        }
    }

    public void Add(T value)
    {
        // Check whether there is still room in the array.
        // If there is not enough room, then increase the capacity
        CheckAndIncreaseIfNecessary();

        // Add the item at the end
        this.items[this.size] = value;
        // Increase the current number of items
        this.size++;
    }

    public void Insert(int index, T value)
    {
        // If the index is the same as the current number of items
        // then call Add() and proceed as if we want to add a new item
        if (index >= size)
        {
            Add(value);
            return;
        }

        // If the index is positive but less than the current size,
        // then you need to insert the item inside the collection.
        if ((index >= 0) && (index < size))
        {
            // Firs, push each item one position up to create
            // an empty space
            for (int i = (size - 1); i > index - 1; i--)
                items[i + 1] = items[i];

            // Then put the new item in the indicated position
            items[index] = value;
            // Since the new item has been added, increase the 
            // current number of items
            size++;
        }
    }

    public bool Contains(T value)
    {
        for (int i = 0; i < Count; i++)
            if (items[i].Equals(value))
                return true;
        return false;
    }

    public int IndexOf(T value)
    {
        for (int i = 0; i < Count; i++)
            if (items[i].Equals(value))
                return i;
        return -1;
    }

    // This method is used to delete an item based on its position
    public void RemoveAt(int index)
    {
        // First check that the user provided a positive index that
        // is lower than the current total number of items
        if ((index >= 0) && (index < size))
        {
            // If so, starting at that index, get the item ahead of
            // each position and assign it to the current item
            for (int i = index; i < size - 1; i++)
                items[i] = items[i + 1];

            // Since the last item is not useful anymore,
            // decrease the number of items
            size--;
        }
    }

    // This method is used to delete an item
    public bool Remove(T value)
    {
        // First try to get the index of the item to find out if it exists
        int index = IndexOf(value);
        
        // If the item was found ...
        if (index >= 0)
        {
            // ... delete it, using its index
            RemoveAt(index);
            // Since the item has been removed, return true
            return true;
        }

        // If the item was not removed (for any reason), return false
        return false;
    }

    // This method is used to delete all items from a collection
    public void Clear()
    {
        // Visit each item in the collection and set it to the default value
        // (This is not really necessary)
        for (int i = 0; i < size; i++)
            items[i] = default(T);

        // Reset the number of items of the collection to 0
        size = 0;
    }

    public IEnumerator<T> GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }
}

Additional Operations on a Collection

Introduction

The operations we saw above are the most regular of a collection. Still, there are many other ways you can assist a user of your collection class by defining more functionality. For example, you can make it possible to add more than one item with a single action, to delete more than one item in one step, to move items inside the collection by changing their positions, etc. The options are infinite as long as you have imagination and want to make your class more useful.

Checking Whether the Collection is Empty

Checking the emptiness of a collection allows you to find out whether it contains at least one item. Probably the easiest way to get this information is to enquire about the total number of items ini the list. This can be done as follows:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // Checks whether the list is empty
    public bool IsEmpty()
    {
        if (size == 0)
            return true;
        return false;
    }
}

public class Exercise
{
    public static int Main()
    {
        Collection<double> numbers = new Collection<double>();

        if (numbers.IsEmpty())
            Console.WriteLine("The list is empty");
        else
            Console.WriteLine("The list contains at least one item");

        numbers.Add(14.88);
        numbers.Add(284.05);
        numbers.Add(8.495);
        numbers.Add(6626.14);
        numbers.Add(3.006);

        if (numbers.IsEmpty())
            Console.WriteLine("The list is empty");
        else
            Console.WriteLine("The list contains at least one item");

        return 0;
    }
}

This would produce:

The list is empty
The list contains at least one item
Press any key to continue . . .

Adding a Collection to a Collection

Instead of adding one item at a time, you can allow a collection to receive a series of items. To do this, you can create a method to which you would pass a collection as argument. In the body of the method, you can use a for loop to navigate from one item to the next. When you get to an item, replace it with an item of the corresponding position of the argument. Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    public void AddRange(T[] values)
    {
        for (int i = 0; i < values.Length; i++)
            Add(values[i]);
    }
}

The First Item of a Collection

A collection that has at least one item has a starting point. There are various ways you can get the first item of a collection. If you are using an array-based list, you can simply get the item at index 0. Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // Gets the first item in the list
    public T First
    {
    	get
    	{
            if (IsEmpty())
                return default(T);

            return items[0];
        }
    }
}

The Last Item of a Collection

If you are using an array-based list, to get the last item, get the item at the total number of items. Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // Gets the last item in the list
    public T Last
    {
        get
        {
            if (IsEmpty())
                return default(T);

            return items[size - 1];
        }
    }
}

Replacing an Item

We saw that, using the indexed property, you can replace an existing item. This operation is not too difficult. You can proceed exactly as done with the set accessor of the indexed property, except that you should check the validity of the index. Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // Replaces an existing item in the list with a new item
    // Equivalent to editing an existing item
    public void Replace(int index, T one)
    {
        if (index < 0)
        {
            // Invalid position
            // Normally, we should throw an exception, such as IndexOutOfRangeException
            return;
        }

        if (index > size)
        {
            // Invalid position
            // Normally, we should throw an exception, such as IndexOutOfRangeException
            return;
        }

        items[index] = one;
    }
}

Moving an Item

Moving an item consists of changing its position. That is, the item's index changes from where it is, the source, to another position, the target. To perform this operation, you can pass two positions to a method. When defining the method, first make sure the positions are valid. Whenever any position is not valid, you should cancel the operation and throw an exception. If the positions are valid:

Here is an example:

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    . . .
    
    // Changes the current position of an existing item.
    // Moves the item from its current curIndex position to the new toIndex position
    public void Move(int curIndex, int toIndex)
    {
        if (curIndex < 0)
        {
            // Invalid starting index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (curIndex > (size - 1))
        {
            // Invalid starting index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (toIndex < 0)
        {
            // Invalid end index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (toIndex > (size - 1))
        {
            // Invalid end index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (curIndex == toIndex)
        {
            // Same index, do nothing
            return;
        }

        // Get the item at the starting position
        T objLower = this[curIndex];

        // Remove the item at the starting position
        RemoveAt(curIndex);
        // move the item to target position
        Insert(toIndex, objLower);
    }
}

Swapping Items

Swapping two items consists of exchanging their positions. That is, the item at index x will move to index y and the item at index y will move to index x. To perform this operation, you pass two positions to a method. In the method, first make sure the positions are valid. If any position is invalid, you should cancel the operation and throw an exception. If the positions are valid:

Here is an example of how this can be done:

using System.Collections.Generic;

public class Collection<T> : IList<T>
{
    private int size;
    private T[] items;

    public Collection()
    {
        size = 0;
        items = new T[10];
    }

    public virtual int Count
    {
        get { return size; }
    }

    // The index property can be used to add an item to a collection,
    // or to retrieve an item from the collection
    public T this[int index]
    {
        get
        {
            return this.items[index];
        }
        set
        {
            this.items[index] = value;
        }
    }

    public void CopyTo(T[] array, int index)
    {
        T[] values = new T[size];

        for (int i = 0; i < size; i++)
            values[i] = items[i];

        array = values;
    }

    public IEnumerator<T> GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        int counter = 0;

        while (counter < Count)
        {
            yield return items[counter];
            counter++;
        }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    private void IncreaseIfNecessary()
    {
        if (size >= items.Length)
            Array.Resize<T>(ref items, items.Length + 5);
    }

    public void Add(T value)
    {
        // Check whether there is still room in the array.
        // If there is not enough room, then increase the capacity
        IncreaseIfNecessary();

        // Add the item at the end
        this.items[this.size] = value;
        // Increase the current number of items
        this.size++;
    }

    public void Insert(int index, T value)
    {
        // If the index is the same as the current number of items
        // then call Add() and proceed as if we want to add a new item
        if (index >= size)
        {
            Add(value);
            return;
        }

        // If the index is positive but less than the current size,
        // then you need to insert the item inside the collection.
        if ((index >= 0) && (index < size))
        {
            // Firs, push each item one position up to create
            // an empty space
            for (int i = (size - 1); i > index - 1; i--)
                items[i + 1] = items[i];

            // Then put the new item in the indicated position
            items[index] = value;
            // Since the new item has been added, increase the 
            // current number of items
            size++;
        }
    }

    public bool Contains(T value)
    {
        for (int i = 0; i < Count; i++)
            if (items[i].Equals(value))
                return true;
        return false;
    }

    public int IndexOf(T value)
    {
        for (int i = 0; i < Count; i++)
            if (items[i].Equals(value))
                return i;
        return -1;
    }
    
    // This method is used to delete an item based on its position
    public void RemoveAt(int index)
    {
        // First check that the user provided a positive index that
        // is lower than the current total number of items
        if ((index >= 0) && (index < size))
        {
            // If so, starting at that index, get the item ahead of
            // each position and assign it to the current item
            for (int i = index; i < size - 1; i++)
                items[i] = items[i + 1];

            // Since the last item is not useful anymore,
            // decrease the number of items
            size--;
        }
    }

    // This method is used to delete an item
    public bool Remove(T value)
    {
        // First try to get the index of the item to find out if it exists
        int index = IndexOf(value);

        // If the item was found ...
        if (index >= 0)
        {
            // ... delete it, using its index
            RemoveAt(index);
            // Since the item has been removed, return true
            return true;
        }

        // If the item was not removed (for any reason), return false
        return false;
    }

    // This method is used to delete all items from a collection
    public void Clear()
    {
        // Visit each item in the collection and set it to the default value
        // (This is not really necessary)
        for (int i = 0; i < size; i++)
            items[i] = default(T);

        // Reset the number of items of the collection to 0
        size = 0;
    }

    // Checks whether the list is empty
    public bool IsEmpty()
    {
        if (size == 0)
            return true;
        return false;
    }

    public void AddRange(T[] values)
    {
        for (int i = 0; i < values.Length; i++)
            Add(values[i]);
    }
    
    // Gets the first item in the list
    public T First
    {
    	get
    	{
            if (IsEmpty())
                return default(T);

            return items[0];
        }
    }

    // Gets the last item in the list
    public T Last
    {
        get
        {
            if (IsEmpty())
                return default(T);

            return items[size - 1];
        }
    }

    // Replaces an existing item in the list with a new item
    // Equivalent to editing an existing item
    public void Replace(int index, T one)
    {
        if (index < 0)
        {
            // Invalid position
            // Normally, we should throw an exception, such as IndexOutOfRangeException
            return;
        }

        if (index > size)
        {
            // Invalid position
            // Normally, we should throw an exception, such as IndexOutOfRangeException
            return;
        }

        items[index] = one;
    }

    // Changes the current position of an existing item.
    // Moves the item from its current curIndex position to the new toIndex position
    public void Move(int curIndex, int toIndex)
    {
        if (curIndex < 0)
        {
            // Invalid starting index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (curIndex > (size - 1))
        {
            // Invalid starting index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (toIndex < 0)
        {
            // Invalid end index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (toIndex > (size - 1))
        {
            // Invalid end index
            // Normally, we should throw an exception, such as IndexOutOfRange
            return;
        }
        if (curIndex == toIndex)
        {
            // Same index, do nothing
            return;
        }

        // Get the item at the starting position
        T objLower = this[curIndex];

        // Remove the item at the starting position
        RemoveAt(curIndex);
        // move the item to target position
        Insert(toIndex, objLower);
    }
        
    // Swaps the positions of two existing items
    // The first item goes to position posSecond
    // and the second item moves to position posFirst
    public void Exchange(int posFirst, int posSecond)
    {
        try
        {
            // Check that posFirst exists
            if (posFirst < 0)
                throw new IndexOutOfRangeException("Invalid first index - Too low");
            // Check that posFirst exists
            if (posFirst > size - 1)
                throw new IndexOutOfRangeException("Invalid first index - Too high");
            // Check that posSecond exists
            if (posSecond < 0)
                throw new IndexOutOfRangeException("Invalid second index - Too low");
            // Check that posSecond exists
            if (posSecond > size - 1)
                throw new IndexOutOfRangeException("Invalid second index - Too high");

            T objFirst = this[posFirst];
            T objSecond = this[posSecond];

            this[posFirst] = objSecond;
            this[posSecond] = objFirst;
        }
        catch (IndexOutOfRangeException)
        {
        }
    }
}

Previous Copyright © 2001-2024, FunctionX Friday 15 October 2021 Home