C#

Generic IList Interface and its Implementation in C#

In this article, I will explain Generic IList Interface and its Implementation in C#. In fact, the .NET Framework library provides a Collections framework that contains the implementation of commonly used data structures. Further, there are generic as well as non-generic collections that exist in the library.

While non-generic collections can work on any type. In contrast, the generic collections work on a specific type that we need to specify at the time of declaration.

This interface is represented as IList<T> and it inherits from the generic ICollection and IEnumerable interfaces respectively. Significantly, this interface has applications in creating generic lists as it provides several important properties and methods.

Details of the IList Interface

The IList interface has a number of properties and methods which we discuss next.

Properties of IList Interface

Basically, this interface declares three properties.

  • Count
  • IsReadOnly
  • Item[Int32]

Firstly, the Count property indicates the total number of elements in the list. Secondly, the IsReadOnly property indicates whether the list is readonly or read-write. Finally, the Items property allows us to add elements to the list as well as to read elements from the list. In fact, the IList interface inherits the Count and the IsReadOnly properties from the ICollection interface.

Methods in Generic IList Interface

The IList interface contains several methods. However, it inherits many of these methods from the ICollection interface. Besides, the IList interface inherits the GetEnumerator() method from the generic IEnumerable interface. Let us discuss these methods one by one.

Add(T obj) method allows us to add a member to the end of the list.

Insert(Int32, T) method takes an index as the first parameter and the object that we want insert as the second parameter. Further, this method inserts the object at specified index if the index is valid.

Contains(T) method is used to search an element which it takes as the parameter and returns a boolean value.

Remove(T) method removes a specific method from the list which is passed as a parameter.

CopyTo(T[], Int32) method copies all the data of the list to an array of specified type starting from a given index.

IndexOf(T) method returns the index of the first occurrence of an element passed as a parameter. Also, if it is not found, the method will return -1.

RemoveAt(Int32) method deletes an element from the specified index.

Clear() method deletes all elements from the list.

GetEnumerator() method returns a custom enumerator.

Generic IList Interface and its Implementation in C#

At this point, let us create a class with the name Employee as shown below. Further, create a list of Employee objects and implement the IList interface for the Employee list.

class Employee
    {
        public string Name { get; set; } = "X";
        public string Designation { get; set; } = "Staff";
        public int Salary { get; set; } = 5000;
        public override string ToString()
        {
            return $"Name: {Name}, Designation: {Designation}, salary: {Salary}";
        }
        public override bool Equals(object obj)
        {
            Employee o = (Employee)obj;
            return Name.Equals(o.Name);
        }
    }

Now create a class called EmpList that implements the generic interface IList as shown below.

class EmpList<Employee>:IList<Employee> {
     }

Define Data Members

Further, define the data members of this class. Therefore, we add the variable cnt to represent the count of elements and the array named staff will have the Employee objects.

class EmpList<Employee>:IList<Employee>
    {
        int cnt = 0;
        Employee[] staff = new Employee[10];
    }

After that, we provide implementation of the GetEnumerator method as shown below. Since, we don’t want to provide a custom enumerator this time, we will not implement this method.

public IEnumerator<Employee> GetEnumerator()
        {
            throw new InvalidOperationException("Employee List is currently not implementing its own enumerator");
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new InvalidOperationException("Employee List is currently not implementing its own enumerator");
        }

Since we are not implementing GetEnumerator right now, the class must have some method to visit the members of the list. Therefore, we provide a method called DisplayList().

public void DisplayList()
        {
            for (int i = 0; i < cnt; i++)
                Console.WriteLine(staff[i]);
        }

Implementation of Properties

Also, our class EmpList should implement three properties namely, Count, IsReadOnly, and the Items property. Therefore, first, implement the Count property. Since it is a readonly property, so it will contain only the get accessor.

public int Count
        {
            get
            {
                return cnt;
            }
        }

Certainly, we want to perform both read and write operations in our list. Hence, the IsReadOnly property should return false.

public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

After that, define the Items property as follows. Basically, it should have both get and set accessors.

public Employee this[int index]
        {
            get
            {
                return staff[index];
            }
            set
            {
                staff[index] = value;
            }
        }

Implementation of Methods

Similarly, we implement the methods of the IList interface as shown below. The Clear() method makes the count of elements to zero and the Add() method will add an element to the list after checking the bounds.

public void Add(Employee e)
        {
            if (cnt < 10)
            {
                staff[cnt] = e;
                cnt++;
            }
        }

        public void Clear()
        {

            cnt = 0;
        }

Evidently, both the Contains() method, and the IndexOf() method check whether the Employee object passed as the parameter is already there in the collection or not. Consequently, the Contains() method returns a boolean value whereas the IndexOf() method returns the corresponding index or -1 depending on whether the element is found or not.

public bool Contains(Employee ob)
        {
            for (int i = 0; i < cnt; i++)
            {
                if (staff[i].Equals(ob))
                    return true;
            }
            return false;
        }
        public int IndexOf(Employee ob)
        {
            for (int i = 0; i < cnt; i++)
            {
                if (staff[i].Equals(ob))
                    return i;
            }
            return -1;
        }

After that, we will define the Insert(), Remove(), and RemoveAt() methods. Basically, the Insert() method will do necessary condition checking and then it will shift some elements to the right before inserting the desired element in the collection. Similarly, the remove() method will shift the elements to the left and decrement the element count by one. However, the Remove() method will call RemoveAt() to delete an element.

 public void Insert(int index, Employee ob)
        {
            if ((cnt + 1 <= staff.Length) && (index >= 0) && (index < cnt))
            {
                cnt++;
                for (int i = cnt - 1; i > index; i--)
                {
                    staff[i] = staff[i - 1];
                }
                staff[index] = ob;
            }
        }
        public bool Remove(Employee ob)
        {
            int p = IndexOf(ob);
            if (p != -1)
            {
                RemoveAt(p);
                return true;
            }
            return false;
        }
        public void RemoveAt(int index)
        {
            if ((index >= 0) && (index < cnt))
            {
                for (int i = index; i < cnt; i++)
                {
                    staff[i] = staff[i + 1];
                }
                cnt--;

            }
        }

Finally, the CopyTo() method copies all the elements of the list to an array of Employee objects starting from a specified index as shown below.

 public void CopyTo(Employee[] arr, int index)
        {
            /*  foreach (Employee e in arr)
                  Console.WriteLine(e);*/
            for (int i = 0; i < cnt; i++)
            {
                arr[index] = staff[i];
                index++;
            }
        }
    }

The Complete Code

As can be seen in the example, the interface defines lots of methods. In order to implement the interface, first we create a class Employee so that, we can create a generic list of type Employee. Further, we create another EmpList that implements the IList interface with the type Employee. For the purpose of storing Employee objects, the EmpList maintains an array of type Employee of size 10.

In order to add an instance of Employee, we define the Add() method that first checks whether the highest index (cnt, in this example) is less than 10. In this case, it assigns the object to the next element of array and increments the value of index. Similarly, the Clear() method makes the index to zero, thereby deleting all elements.

Similarly, we need to define other methods of the interface such as Contains(), IndexOf(), Insert(), Temove(), RemoveAt(), and CopyTo(). Additionally, the EmpList class also defines GetEnumerator() method.

Generic IList Interface and its Implementation in C# is given below.

Now that, we have implemented the interface, then we can use it by creating an array of Employee and creating the EmpList using that array and call various methods of the EmpList.

using System;
using System.Collections.Generic;
using System.Collections;
namespace GenericIListInterfaceExample
{
    class Employee
    {
        public string Name { get; set; } = "X";
        public string Designation { get; set; } = "Staff";
        public int Salary { get; set; } = 5000;
        public override string ToString()
        {
            return $"Name: {Name}, Designation: {Designation}, salary: {Salary}";
        }
        public override bool Equals(object obj)
        {
            Employee o = (Employee)obj;
            return Name.Equals(o.Name);
        }
    }

    class EmpList<Employee> : IList<Employee>
    {
        int cnt = 0;
        Employee[] staff = new Employee[10];
        public IEnumerator<Employee> GetEnumerator()
        {
            throw new InvalidOperationException("Employee List is currently not implementing its own enumerator");
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new InvalidOperationException("Employee List is currently not implementing its own enumerator");
        }
        public void DisplayList()
        {
            for (int i = 0; i < cnt; i++)
                Console.WriteLine(staff[i]);
        }

        public void Add(Employee e)
        {
            if (cnt < 10)
            {
                staff[cnt] = e;
                cnt++;
            }
        }

        public void Clear()
        {

            cnt = 0;
        }

        public int Count
        {
            get
            {
                return cnt;
            }
        }

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

        public Employee this[int index]
        {
            get
            {
                return staff[index];
            }
            set
            {
                staff[index] = value;
            }
        }
        public bool Contains(Employee ob)
        {
            for (int i = 0; i < cnt; i++)
            {
                if (staff[i].Equals(ob))
                    return true;
            }
            return false;
        }
        public int IndexOf(Employee ob)
        {
            for (int i = 0; i < cnt; i++)
            {
                if (staff[i].Equals(ob))
                    return i;
            }
            return -1;
        }
        public void Insert(int index, Employee ob)
        {
            if ((cnt + 1 <= staff.Length) && (index >= 0) && (index < cnt))
            {
                cnt++;
                for (int i = cnt - 1; i > index; i--)
                {
                    staff[i] = staff[i - 1];
                }
                staff[index] = ob;
            }
        }
        public bool Remove(Employee ob)
        {
            int p = IndexOf(ob);
            if (p != -1)
            {
                RemoveAt(p);
                return true;
            }
            return false;
        }
        public void RemoveAt(int index)
        {
            if ((index >= 0) && (index < cnt))
            {
                for (int i = index; i < cnt; i++)
                {
                    staff[i] = staff[i + 1];
                }
                cnt--;

            }
        }

        public void CopyTo(Employee[] arr, int index)
        {
            /*  foreach (Employee e in arr)
                  Console.WriteLine(e);*/
            for (int i = 0; i < cnt; i++)
            {
                arr[index] = staff[i];
                index++;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Employee[] arr = new Employee[]
            {
                new Employee{Name="A", Designation="Manager", Salary=45000},
                new Employee{Name="B", Designation="Cleark", Salary=15000},
                new Employee{Name="C", Designation="Programmer", Salary=35000},
                new Employee{Name="D", Designation="Operator", Salary=25000},
                new Employee{Name="E", Designation="Driver", Salary=15000},
                new Employee{Name="F", Designation="Manager", Salary=50000},
            };

            EmpList<Employee> list1 = new EmpList<Employee>();
            Console.WriteLine($"Count: {list1.Count}");
            Console.WriteLine("Adding Elements...");
            for (int i = 0; i < arr.Length; i++)
            {
                list1.Add(arr[i]);
            }
            Console.WriteLine("List Elements...");
            list1.DisplayList();
            Console.WriteLine($"Count: {list1.Count}");

            Employee e = new Employee { Name = "xyz", Designation = "Clerk", Salary = 17000 };
            Console.WriteLine("Inserting in Employee List...");
            list1.Insert(4, e);
            list1.DisplayList();
            Console.WriteLine($"Count: {list1.Count}");

            Employee e1 = new Employee { Name = "B" };
            Console.WriteLine("Removing an element from the list...");
            list1.Remove(e1);
            list1.DisplayList();
            Console.WriteLine($"Count: {list1.Count}");

            Console.WriteLine("Removing another element from the list...");
            list1.RemoveAt(5);
            list1.DisplayList();
            Console.WriteLine($"Count: {list1.Count}");

            Employee[] arr1 = new Employee[20];
            for (int i = 0; i < 20; i++)
                arr1[i] = new Employee();
            Console.WriteLine("CopyTo method...");
            list1.CopyTo(arr1, 7);
            Console.WriteLine("Resulting Array...");
            foreach (Employee ob in arr1)
                Console.WriteLine(ob);

            Console.WriteLine("Searching Elements in the list...");
            Employee e3 = new Employee { Name = "A" };
            Employee e4 = new Employee { Name = "S" };
            Console.WriteLine($"Employee List Contains A: {list1.Contains(e3)}");
            Console.WriteLine($"Employee List Contains S: {list1.Contains(e4)}");

            Employee e5 = new Employee { Name = "E" };

            Console.WriteLine($"Index of A: {list1.IndexOf(e3)}");
            Console.WriteLine($"Index of S: {list1.IndexOf(e4)}");
            Console.WriteLine($"Index of E: {list1.IndexOf(e5)}");

            Console.WriteLine($"Is List Read Only: {list1.IsReadOnly}");

            Console.WriteLine("Clearing the List...");
            list1.Clear();
            list1.DisplayList();
            Console.WriteLine($"Count: {list1.Count}");
        }
    }
}

Output

Demonstration of Generic IList Interface and its Implementation in C#
Demonstration of Generic IList Interface and its Implementation in C#

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *