DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 3.18 Calling the Same Method on Multiple Object Types

Problem

You need to perform a particular action on a set of dissimilar objects contained within an array or collection, preferably without having to know each individual object's type.

Solution

Use interfaces in a polymorphic manner. The following interface contains a single method, Sort, which allows sorting to be performed on the object that implements this interface:

public interface IMySort
{
    void Sort( );
}

The next three classes implement the IMySort interface. These classes all share the same Sort method, but each class implements it in a different way:

public class CharContainer : IMySort
{
    public void Sort( )
    {
        // Do character type sorting here

        Console.WriteLine("Characters sorted");
    }
}

public class NumberContainer : IMySort
{
    public void Sort( )
    {
        // Do numeric type sorting here

        Console.WriteLine("Numbers sorted");
    }
}

public class ObjectContainer : IMySort
{
    public void Sort( )
    {
        // Do object type sorting here

        Console.WriteLine("Objects sorted");
    }
}

The SortAllObjects method accepts an array of objects :

public void SortAllObjects(IMySort[] sortableObjects)
{
    foreach (IMySort m in sortableObjects)
    {
        m.Sort( );
    }
}

If this method is called as follows:

Obj.SortAllObjects(new IMySort[3] {new CharContainer( ), 
                                  new NumberContainer( ), 
                                  new ObjectContainer( )});

the following is displayed:

Characters sorted
Numbers sorted
Objects sorted

Discussion

The foreach loop is useful not only for iterating over individual elements in a collection or an array, but also in iterating over a specific interface implemented by each element in a collection or array. Using this technique, interface members may be used in a similar manner on each element, even if the elements are unrelated object types. Consider the following array of objects:

Object[] objs = new Object[6] {new CharContainer( ), 
                               new NumberContainer( ),
                               new CharContainer( ), 
                               new ObjectContainer( ),
                               new NumberContainer( ), 
                               new ObjectContainer( )});

This array contains several objects of differing types. The one thread of similarity that runs through each type is the implementation of the IMySort interface, defined as follows:

public interface IMySort
{
    void Sort( );
}

Passing the Objects array in to the following method allows each Sort method to be called from each object in the Objects array:

public void SortAllObjects(object[] sortableObjects)
{
    foreach (IMySort m in sortableObjects)
    {
        m.Sort( );
    }
}

The foreach loop in this method is able to treat each object in the sortableObjects array in the same way because each object in the sortableObjects array is cast to its IMySort interface and used as such.

If the foreach loop encounters a sortableObjects array that contains one or more objects that do not implement the IMySort interface, an InvalidCastException will be thrown. To prevent an exception from being thrown while at the same time allowing the foreach loop to iterate over all elements in the sortableObjects array, you can use the following modified code:

public void SortAllObjects(object[] sortableObjects)
{
    foreach (object o in sortableObjects)
    {
        IMySort sortObject = o as IMySort;
        if (sortObject!= null)
        {
            sortObject.Sort( );
        }
    }
}

This modified method will now test each element of the sortableObjects array to first determine whether it can be cast to an IMySort interface. If it can be cast to this interface type, the variable sortObject will not be null and the if statement will allow the Sort method on that object to be called.

See Also

See the "interface" keyword, "Base Class Usage Guidelines," and "When to Use Interfaces" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section