Interfaces and Polymorphism

Understanding Interfaces

Interfaces define contracts that classes can implement. They specify the methods and properties a class must provide, ensuring compatibility. Consider this example:

// Interface definition in `DefaultableCollection.cs`
          public interface ICollection<T>
          {
              // ... methods and properties
          }
          

The ICollection<T> interface outlines the behavior of a collection type. Any class implementing this interface must provide the methods and properties defined within the interface, ensuring consistent behavior across different collection types.

Polymorphism: Enabling Flexibility

Polymorphism allows objects of different types to be treated as objects of a common type through inheritance and interfaces. In our example, the DefaultableCollection class implements the ICollection<T> interface:

// Implementation in `DefaultableCollection.cs`
          public class DefaultableCollection<T> : ICollection<T>
          {
              // ... implementation of ICollection<T> methods
          }
          

This implementation means instances of DefaultableCollection<T> can be used where an ICollection<T> is expected, allowing flexibility and extensibility. Code can interact with collections using the interface, without needing to know the concrete type of collection being used.

Example: Using Interfaces and Polymorphism

// Example usage in `Program.cs`
          public static void Main(string[] args)
          {
              // Creating a DefaultableCollection instance
              DefaultableCollection<int> collection = new DefaultableCollection<int>();
          
              // Adding elements to the collection
              collection.Add(1);
              collection.Add(2);
              collection.Add(3);
          
              // Iterating through the collection using the ICollection<T> interface
              foreach (int item in collection)
              {
                  Console.WriteLine(item);
              }
          }
          

In this example, we use the ICollection<T> interface to iterate through the DefaultableCollection<T> instance. The code doesn’t need to know that it’s a DefaultableCollection<T>; it only uses the methods provided by the ICollection<T> interface, making the code more flexible and maintainable.