8.4. Interfaces In The Wild

The first situations where you’ll want to use interfaces involve applying pre-defined interfaces and classes that are part of C#. In fact, you have already encountered implementations of several these System provided interfaces.

8.4.1. IComparer<T>

Purpose: A class implements this interface to compare two objects of a given class. This is a parameterized interface, which means that when using it, you need to specify the class that it will be comparing. For example, IComparer<Job> would compare Job objects.

Important Methods and Properties: Compare(T, T)

IComparer.Compare Documentation

This interface can be used to determine, given two objects of the given type, which one is greater than the other. It is also used by collections such as List to sort its contents with the Sort method.

Using IComparer<T> is a two step process. You must first create a class that implements the interface. Then, provide a custom implementation of the Compare method:

Example

public class JobComparer : IComparer<Job>
{
   public int Compare(Job x, Job y)
   {
      // ^^ This Compare method is an implementation of IComparer.Compare
      // Here, we write our own logic for comparing two job objects.
      // For example, if we want to compare Job objects by name values, we'd write:
      return string.Compare(x.Name, y.Name);
      // ^^ Note, this Compare method is the built-in string method
      // if we want to compare Jobs based on multiple fields, we can do so by expanding the custom logic
      // in this ``IComparer.Compare`` implementation
   }
}

Compare(T, T) returns an integer which determines which of the two objects comes before (in other words, “is less than”) the other. If the returned value is less than zero, then the first parameter comes before the second. If the integer is zero, then they are considered the same. If the integer is greater than zero, then the second parameter comes before the first.

You can think of the result of calling Compare(x, y) as being the value of subtracting, like x - y. If x is smaller than y, this value is negative. If x is larger than y, this value is positive.

8.4.2. IEnumerable<T>

Purpose: Enable iteration over a collection of objects using foreach.

Important Methods and Properties: MoveNext(), Current

IEnumerable<T> Documentation

This interface is implemented by the List<T> class, which we’ve been using throughout this course.

Example

IEnumerable<string> collection = new List<string>();

// add items to the collection

foreach (string item in collection)
{
   // do something with the item
}

Indeed, if you so desire, you may replace other instances of List with this interface as long as those interfaces don’t require specifically List methods.

8.4.3. IList<T>

Purpose: Enable access to objects in a collection by index.

Important Methods and Properties: Add(T), Contains(T), Remove(T), Count

IList<T> Documentation

This interface is also implemented by the List<T> class, which we’ve been using throughout this course. In fact, IList<T> extends IEnumerable<T>. An interface may extend another interface, in the same way that classes may extend each other.

Example

IList<string> collection = new List<string>();

// Add items to the collection

string firstItem = collection[0];

8.4.4. IDictionary<TKey, TValue>

Purpose: Represent a collection of key/value pairs.

Important Methods and Properties: Add(TKey, TValue), Contains(T), Remove(T), Count, Keys, Values

IDictionary<TKey, TValue> Documentation

This interface is implemented by the Dictionary<TKey, TValue> class, which we’ve been using throughout this course.

Example

IDictionary<string, string> collection = new Dictionary<string, string>();

// Add items to the collection

// Get item with key "hello"
string hello = collection["hello"];

8.4.5. Check Your Understanding

Question

True or False

An interface can extend another interface.