Home

ASP.NET Collections: The IList Interface

 

IList Fundamentals

 

Introduction

While it provides the minimum functionality of a collection, the System.Collections.ICollection (and the System.Collections.Generic.ICollection) interface is not equipped to perform the regular operations of a collection class, such as adding, retrieving, or deleting items from a set.

To assist you with creating a collection class as complete as possible, the .NET Framework provides an interface named IList. The IList interface is defined in the System.Collections namespace and its equivalent of the same name is defined in the System.Collections.Generic namespace. The interface is equipped with the methods necessary to add, insert, delete, or retrieve items from a collection. Because the functionalities of these methods may not suit you, to use these features, you must create a class that implements them.

 

Implementing IList

As mentioned above, to create a collection, you can derive it from the IList interface. Here is an example:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
	public BookList()
	{
		
	}
}

This System.Collections.IList interface is declared as follows:

public interface IList : ICollection, IEnumerable

This System.Collections.Generic.IList interface is declared as follows:

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

This means that the IList interface exdends both the ICollection and the IEnumerable interfaces. This also implies that you must implement the members of these parent interfaces. In other words, you must implement the Count property, the SyncRoot property, the IsSynchronized property, and the CopyTo() method of the ICollection interface. From what we learned with ICollection, here are examples of implementing these members for the System.Collections.IList interface:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    private int counter;
    private object[] objs;

    public BookList()
    {
        counter = 0;
        objs = new array[5];
    }

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

    public virtual bool IsSynchronized
    {
        get { return false; }
    }

    public virtual object SyncRoot
    {
        get { return this; }
    }

    public virtual void CopyTo(Array ary, int index)
    {
    }
}

You must also implement the System.Collections.GetEnumerator() (or the System.Collections.Generic.GetEnumerator()) method of the System.Collections.IEnumerable  (or of the System.Collections.Generic.IEnumerable) interface. If you do not have time to completely implement it, you can simply return null. Here is an example for the System.Collections.IList interface:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public IEnumerator GetEnumerator()
    {
        return null;
    }
}

The Size of a Collection

 

A Fixed-Size Collection

In the next sections, we will see how to add values to a list of a database. As you add or insert values in a list, the Count property grows. If your collection is array-based, when you start it, you specify the number of values that the list will contain. In theory, you cannot add new values beyond that number. In reality, you can increase the size of an array and then add a new item. If your collection is a linked list, you are also not confined to the laws of space (unless your computer runs out of memory).

If you create a list whose number of values must be constant, the user cannot add values beyond the maximum allowed number. Therefore, before adding a value, you can first check whether the collection has a fixed size or not. To give you this information, the IList interface is equipped with a Boolean read-only property named IsFxedSize. This property simply lets the user know whether the collection has a fixed number of items.

Here is an example of implementing this property for the System.Collections.IList interface:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public virtual bool IsFixedSize
    {
        get { return false; }
    }
}

A Read-Only Collection

Most databases are meant to receive new values. If you want, you can create a list that cannot receive new values. To support this, the IList interface is equipped with the Boolean IsReadOnly property. If a list is read-only, it would prevent the clients from adding items to it.

Here is an example of implementing the IsReadOnly property for the System.Collections.IList interface:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

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

Populating the Collection

 

Adding an Item

As it should be obvious, the primary operation to perform on a list is to populate it with at least one value. To support this, the System.Collections.IList interface is equipped with a method named Add. Its syntax is:

int Add(object value);

This method takes one argument as the value to add to the list. 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 System.Collections.IList interface:

  • If there is still room in the collection, the value would be added to the list
  • If there is not enough room, the value would simply not be added. There would not be a problem and the program would not crash. In fact, no exception would be thrown if the value was not added because of lack of space. On the other hand, since the compiler would not let you know that there was a problem with "logistic", you may not know whether the value was added or not. Therefore, if you are concerned with knowing whether the value was added, you must provide this functionality yourself 

If the method succeeds with the addition, it returns the position where the value was added in the list. This is usually the last position in the list.

Here is an example:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public virtual int Add(object value)
    {
        // Check whether there is still room in
        // the array to add a new item
        if (counter < objects.Length)
        {
            // Since there is room, put the new item to the end
            objects[items] = value;
            // increase the number of items
            objects++;
            // Return the index of the item that was added
            return counter - 1;
        } // Since the item could not be added, return a negative index
        else
            return -1;
    }
}

Inserting an Item

When you call the System.Collections.IList.Add() method, it adds the new value to the end of the list. Sometimes, you will want the new value to be insert somewhere inside the list. To support this operation, both the System.Collections.IList and the System.Collections.Generic.IList interfaces provide a method named Insert. The syntax of the System.Collections.IList.Insert() method is:

void Insert(int index, object value);

The syntax of the System.Collections.Generic.IList.Insert() 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. Because this method takes an Object object, if your collection is using a different type of value, you may have to cast it to Object. The first argument is the index of the item that will precede the new one.

As mentioned for the System.Collections.IList. Add() method, there are a few things you should know about this operation's success or lack of it:

  • If the index argument holds a negative value or a value higher than the allowed number (for example if the list is an array) of the items (depending on how you implement the method), the new value would not be added, the compiler would not throw an exception, and therefore nothing would let you know that the value was not added. If you want to find out whether the value was formally or actually inserted or not, you must create the functionality yourself
  • If the value argument is not valid, again depending on how you structure your class, either the value would not be inserted or something else would go wrong. Fortunately, if the value argument is of the type of a class you created yourself, the compiler would produce an error such as letting you know that the argument is holding a value that is not conform to its property or member variable

Locating an Item in the Collection

 

This Default Item of the Collection

While using a list, various operations require that you know the object you are currently accessing. To provide this operation, you must create an indexed property. This property should take an index and return the type of object that makes up the list. Here is an example:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public virtual object this[int index]
    {
        get { return objects[index]; }

        set
        {
            objects[index] = value;
        }
    }
}

After creating this property, you can then access an item using its index and applying the [] operator on its instance. Remember that if you want to use foreach, you must appropriately implement the IEnumerable.GetEnumerator() method.

Enumerating the Collection foreach Item

One of the most valuables features of the C# is the ability to use the foreach loop to enumerate the members of a collection. To make this possible, you must implement the IEnumerator interface in your collection class. Following the rules of interface implementation, you must override the members of IEnumerator

Checking the Existence of 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 System.Collections.IList interface is equipped with a method named Contains. Its syntax is:

bool Contains(object value);

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

Here is an example of implementing this method:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public bool Contains(object value)
    {
        for (int i = 0; i < Count; i++)
            if (objects[i] == value)
                return true;
        return false;
    }
}

This method calls the Equals() method of the objects that make up the list to find out whether the value argument exists in the collection. If this method produces a wrong result, especially if you are using your own class to represent the item, you may have to override your own Equals() method.

Getting the Index of an Item

The System.Collections.IList.Contains() method is used to check whether a particular value (already) exists in the collection. If you know that a certain item exists in the collection 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(object value);

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:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public int IndexOf(object value)
    {
        for (int i = 0; i < Count; i++)
            if (objects[i] == value)
                return i;
        return -1;
    }
}

This method calls the Equals() method of the objects that make up the collection to find out whether the value argument exists in the list. If this method produces a wrong result, especially if you are using your own class to represent the value, you may have to override your own Equals() method.

Deleting Values in the List

 

Deleting a Value by its Index

If a value is not necessary in your list, you can delete it. Probably the simplest way to delete a value is to specify its position in the list. To support this operation, both the System.Collections.IList and the System.Collections.Generic.IList interfaces are equipped with a method named RemoveAt. The syntax of the RemoveAt() method is is the same for both interfaces and it is:

void RemoveAt(int index);

This method takes as argument the index of the value to be removed. Here is an example:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public void RemoveAt(int index)
    {
        if ((index >= 0) && (index < Count))
        {
            for (int i = index; i < Count - 1; i++)
                objects[i] = objects[i + 1];
            items--;
        }
    }
}

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 System.Collections.IList interface is equipped with a method named Remove() and whose syntax is:

void Remove(object value);

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 (the compiler doesn't throw an exception. Here is an example of implementing this method:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    . . . No Change

    public virtual void Remove(Object value)
    {
        RemoveAt(IndexOf(value));
    }
}

Clearing a Collection

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

void Clear();

Here is an example of implementing it:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

/// <summary>
/// Summary description for BookList
/// </summary>
public class BookList : IList
{
    private int counter;
    private object[] objects;

    public BookList()
    {
        counter = 0;
        objects = new object[5];
    }

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

    public virtual bool IsSynchronized
    {
        get { return false; }
    }

    public virtual object SyncRoot
    {
        get { return this; }
    }

    public virtual void CopyTo(Array ary, int index)
    {
    }

    public IEnumerator GetEnumerator()
    {
        return null;
    }

    public virtual bool IsFixedSize
    {
        get { return false; }
    }

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

    public virtual int Add(object value)
    {
        // Check whether there is still room in
        // the array to add a new item
        if (counter < objects.Length)
        {
            // Since there is room, put the new item to the end
            objects[counter] = value;
            // increase the number of items
            counter++;
            // Return the index of the item that was added
            return counter - 1;
        } // Since the item could not be added, return a negative index
        else
            return -1;
    }

    public virtual void Insert(int index, object value)
    {
    }

    public virtual object this[int index]
    {
        get { return objects[index]; }

        set
        {
            objects[index] = value;
        }
    }

    public virtual bool Contains(object value)
    {
        for (int i = 0; i < Count; i++)
            if (objects[i] == value)
                return true;
        return false;
    }

    public virtual int IndexOf(object value)
    {
        for (int i = 0; i < Count; i++)
            if (objects[i] == value)
                return i;
        return -1;
    }

    public virtual void RemoveAt(int index)
    {
        if ((index >= 0) && (index < Count))
        {
            for (int i = index; i < Count - 1; i++)
                objects[i] = objects[i + 1];
            counter--;
        }
    }

    public virtual void Remove(Object value)
    {
        RemoveAt(IndexOf(value));
    }

    public virtual void Clear()
    {
        counter = 0;
    }
}
 

Previous Copyright © 2009 C# Key Home