Interfaces in C# are a fundamental concept for achieving abstraction and defining contracts for classes. They specify a set of members (methods, properties, events, indexers) that a class must implement if it chooses to implement the interface.
An interface is similar to an abstract class, but it can only contain abstract members. It defines a blueprint of what a class can do, without specifying how it does it. An interface cannot contain any implementation details, only declarations.
You declare an interface using the interface keyword. The following is an example of an interface named IAnimal:
public interface IAnimal
{
string Name { get; }
void MakeSound();
void Move();
}
A class implements an interface by using a colon (:) followed by the interface name. The class must then provide implementations for all members declared in the interface.
public class Dog : IAnimal
{
public string Name { get; private set; }
public Dog(string name)
{
Name = name;
}
public void MakeSound()
{
Console.WriteLine("Woof!");
}
public void Move()
{
Console.WriteLine("Running...");
}
}
public class Cat : IAnimal
{
public string Name { get; private set; }
public Cat(string name)
{
Name = name;
}
public void MakeSound()
{
Console.WriteLine("Meow!");
}
public void Move()
{
Console.WriteLine("Creeping...");
}
}
You can use interface types to refer to objects of classes that implement the interface. This allows for polymorphic behavior and easier management of collections of objects with similar capabilities.
IAnimal myDog = new Dog("Buddy");
IAnimal myCat = new Cat("Whiskers");
myDog.MakeSound(); // Output: Woof!
myCat.Move(); // Output: Creeping...
// Example with a list of animals
List<IAnimal> zoo = new List<IAnimal>();
zoo.Add(myDog);
zoo.Add(myCat);
foreach (var animal in zoo)
{
Console.WriteLine($"Processing {animal.Name}:");
animal.MakeSound();
animal.Move();
}
Interfaces can inherit from other interfaces. This allows for the creation of hierarchies of interfaces.
public interface IPet : IAnimal
{
string OwnerName { get; set; }
void Play();
}
public class Hamster : IPet
{
public string Name { get; private set; }
public string OwnerName { get; set; }
public Hamster(string name, string owner)
{
Name = name;
OwnerName = owner;
}
public void MakeSound() { /* ... */ }
public void Move() { /* ... */ }
public void Play() { Console.WriteLine("Running in wheel!"); }
}
Prior to C# 8.0, interfaces could only contain declarations. With the introduction of default interface methods (C# 8.0 and later), interfaces can now include method implementations. This provides a way to evolve interfaces without breaking existing implementations.
You can provide a default implementation for a method directly within the interface. Classes implementing the interface can either use this default implementation or provide their own override.
public interface ILogger
{
void Log(string message);
// Default implementation
void LogError(string errorMessage)
{
Log($"ERROR: {errorMessage}");
}
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"[LOG] {message}");
}
// ConsoleLogger will automatically have the LogError method from the interface
}
// A class that overrides the default method
public class FileLogger : ILogger
{
public void Log(string message)
{
// Write to a file...
Console.WriteLine($"[FILE LOG] {message}");
}
// Override the default LogError method
public new void LogError(string errorMessage)
{
Console.WriteLine($"[FILE LOGGER ERROR HANDLER] Critical error: {errorMessage}");
// More sophisticated error handling, like writing to a specific error file
}
}
Interfaces define 'what' a class can do, while classes define 'how' it does it. They are a cornerstone of object-oriented design in C#.