Home

Implementing a Collection Using .NET

   

Common Behaviors of Collections

 

Introduction

Although you can create a collection class from nothing, most collections class have some fundamental behaviors and characteristics. To give a skeleton of these default requirements, the .NET Framework provides a few interfaces that you can implement. For example the System.Collections.IComparer or the System.Collections.Generic.IComparer interfaces allow you to define how two objects would be compared for similarity or difference.

The System.Collections.IDictionary or the System.Collections.Generic.IDictionary interface can be used to create a collection class where each item is made of a  key=value combination.

Introduction to the ICollection Interface

One of the primary pieces of information you should provide about the values in a database is the number of values that a list is (currently) holding. When creating a collection class, to prepare it to provide this valuable information, you can (should) implement an interface named ICollection. The ICollection interface is defined in the System.Collections namespace. The ICollection interface derives from the IEnumerable initerface:

public interface ICollection : IEnumerable

The generic equivalent of the ICollection interface is defined in the System.Collections.Generic namespace. The ICollection<> interface inherits from the IEnumerable<> and the IEnumerable interfaces:

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

Therefore, to start a collection class, you can creating implement one of these interfaces. Here is an example for the System.Collections.ICollection<> interface:

using System;
using System.Collections;

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

Thanks to the flexibility of arrays in the .NET Framework, you can create the items of the collection as an array and give it an initial size. Here is an example:

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

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

Implementing ICollection

To assist you with keeping track of the number of items in a collection, the ICollection<T> interface is equipped with an integral property named Count, which you must implement. To do this, you can create a private member variable that will actually keep a count of the number of items. The Count property can then be used to communicate this information to the clients of the class. Here is an example:

using System;
using System.Collections;

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

    public Collection()
    {
        size = 0;
    }

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

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 index of the item from where the copying operation will begin. Here is an example:

public class Collection<T> : ICollection<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;
    }
}

The System.Collections.ICollection.ICollection (and the System.Collections.Generic) interface extends the IEnumerable<> interface. This means that you should be able to use foreach in your ICollection<>-based class but you must create the functionality yourself, which is done by implementing the GetEnumerator() method. Because the ICollection<> interface inherits from IEnumerable<> that itself inherits from IEnumerable, you must implement two versions of the GetEnumerator() methods. As we saw in the previous lesson, their syntaxes are:

IEnumerator<T> GetEnumerator();
IEnumerator GetEnumerator();

Even if you don't want to support this feature, you still must provide at least a skeleton for this method. Here is an example:

public class Collection<T> : ICollection<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++;
        }
    }
}

The IList Interface

 

Introduction

While it provides the minimum functionality of a collection, the System.Collections.Generic.ICollection<> (and the System.Collections.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 the IList<> (and the IList) interface. The IList<> interface is defined in the System.Collections.Generic namespace and its non-generic equivalent of the same name is defined in the System.Collections 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

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

As mentioned above, to create a collection, you can implement the IList<> interface. Here is an example:

using System;
using System.Collections.Generic;

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

This means that the IList<> interface extends the ICollection<>, the IEnumerable<>, and the IEnumerable interfaces. This also implies that you must implement the members of these parent interfaces, including the Count, the IsReadOnly properties, the CopyTo(), and the GetEnumerator() method. From what we learned with ICollection, here are examples of implementing these members 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++;
        }
    }
}

Populating the Collection

 

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 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:

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; }
    }

    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++;
        }
    }
}

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 IList<> interface is equipped with a method named Add. 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 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

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 int Add(double item)
    {
        this.items[this.size] = item;
        this.size++;

        return 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 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++;
    }
}

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, 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 the System.Collections.IList.Insert() method takes an object value, 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 a fixed 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

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++;
        }
}

When calling the IList<>.Insert() method, if you pass an invalid index, the compiler would throw an ArgumentOutOfRangeException.

Locating an Item in the Collection

 

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, IList and the IList<> interfaces are 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; }

If you implement it right, this property can perform one of three operations:

  • If you pass it an index that is the same number as the items in the collection and assign a value to it, it allows you to add an item at the end of the collection
  • If you give it a positive index that is lower than the total number of items in the list and assign a value to it, it replaces the item at that position with the new value
  • It you get the value at a positive index that is lower than the total number, it produces the item at that position

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.

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 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;
    }
}

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 should override the Equals() method.

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;
    }
}

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, 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. 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--;
        }
    }
}

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

Clearing a Collection

To remove all values from a list at once, you can implement 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;
    }
}

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 an argument 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];
        }
    }
}

Fortunately, remember that the IList<> is derived from the IEnumerable<> interface. That interface is equipped with a method named First. Its syntax is:

public static TSource First<TSource>(this IEnumerable<TSource> source);

This method allows you to get the first member of a collection.

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];
        }
    }
}

Remember that the IList<> derives from the IEnumerable<> interface. That interface provides a method named Last. Its syntax is:

public static TSource Last<TSource>(this IEnumerable<TSource> source);

This method allows you to get the first member of a collection.

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:

  • Save the item of the source position to a temporary object
  • Delete the item at the target index
  • Insert the saved item in the target index

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:

  • Temporarily save one of the items
  • Temporarily save the other item
  • Put the first saved item in the other position by replacing it
  • Put the other saved item in the first position by replacing it

Here is an example of how this can be done:

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

    . . .
    
    // 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)
        {
        }
    }
}
 

Home Copyright © 2010-2016, FunctionX