C# interfaces — define, implement, explicit implementation, and interface vs abstract class

An interface defines a contract — a set of members that any implementing type must provide. Interfaces enable polymorphism and dependency injection without requiring inheritance from a common base class.

Defining an Interface

C# Example Code
public interface IAnimal
{
    string Name { get; }
    void Speak();
}

By convention, interface names start with I. Members are public by default — no access modifiers needed.

Implementing an Interface

C# Example Code
public interface IAnimal
{
    string Name { get; }
    void Speak();
}

public class Dog : IAnimal
{
    public string Name { get; }

    public Dog(string name) => Name = name;

    public void Speak() => Console.WriteLine($"{Name} says: Woof!");
}

public class Cat : IAnimal
{
    public string Name { get; }

    public Cat(string name) => Name = name;

    public void Speak() => Console.WriteLine($"{Name} says: Meow!");
}

IAnimal[] animals = { new Dog("Rex"), new Cat("Whiskers") };
foreach (var a in animals)
    a.Speak();

// Rex says: Woof!
// Whiskers says: Meow!

Interface Properties and Methods

Interfaces can declare properties, methods, indexers, and events — but not fields.

C# Example Code
public interface IShape
{
    double Area    { get; }          // property
    double Perimeter { get; }        // property
    string Describe();               // method
}

public class Rectangle : IShape
{
    public double Width  { get; }
    public double Height { get; }

    public Rectangle(double width, double height)
    {
        Width  = width;
        Height = height;
    }

    public double Area      => Width * Height;
    public double Perimeter => 2 * (Width + Height);
    public string Describe() => $"Rectangle {Width}×{Height}";
}

IShape s = new Rectangle(4, 3);
Console.WriteLine(s.Area);       // 12
Console.WriteLine(s.Describe()); // Rectangle 4×3

Implementing Multiple Interfaces

A class can implement any number of interfaces (unlike inheritance, which is limited to one base class).

C# Example Code
public interface IReadable
{
    string Read();
}

public interface IWritable
{
    void Write(string value);
}

public interface IReadWritable : IReadable, IWritable { }  // interface inheritance

public class Buffer : IReadWritable
{
    private string _data = "";

    public string Read()              => _data;
    public void   Write(string value) => _data = value;
}

var buf = new Buffer();
buf.Write("Hello!");
Console.WriteLine(buf.Read()); // Hello!

Explicit Interface Implementation

Use explicit implementation when two interfaces have conflicting member names, or to hide a member from the default view of the class.

C# Example Code
public interface IEnglishGreeter
{
    string Greet();
}

public interface ISpanishGreeter
{
    string Greet();
}

public class Bilingual : IEnglishGreeter, ISpanishGreeter
{
    // Explicit — accessible only via the interface type
    string IEnglishGreeter.Greet() => "Hello!";
    string ISpanishGreeter.Greet() => "¡Hola!";
}

var b = new Bilingual();
// b.Greet(); // Compile error — ambiguous

IEnglishGreeter en = b;
ISpanishGreeter es = b;
Console.WriteLine(en.Greet()); // Hello!
Console.WriteLine(es.Greet()); // ¡Hola!

Default Interface Methods (C# 8+)

Interfaces can now include method implementations. This lets you add new members to an interface without breaking existing implementors.

C# Example Code
public interface ILogger
{
    void Log(string message);

    // Default implementation — optional to override
    void LogError(string message) => Log($"[ERROR] {message}");
    void LogInfo(string message)  => Log($"[INFO]  {message}");
}

public class ConsoleLogger : ILogger
{
    // Only required member
    public void Log(string message) => Console.WriteLine(message);

    // LogError and LogInfo are inherited from the interface
}

ILogger logger = new ConsoleLogger();
logger.LogInfo("App started");   // [INFO]  App started
logger.LogError("Disk full");    // [ERROR] Disk full

Interfaces with Generics

C# Example Code
public interface IRepository<T>
{
    T?   GetById(int id);
    void Save(T item);
    IEnumerable<T> GetAll();
}

public class InMemoryProductRepository : IRepository<Product>
{
    private readonly List<Product> _store = new();

    public Product? GetById(int id) => _store.FirstOrDefault(p => p.Id == id);
    public void Save(Product item)  => _store.Add(item);
    public IEnumerable<Product> GetAll() => _store.AsReadOnly();
}

record Product(int Id, string Name);

Interface vs Abstract Class

InterfaceAbstract class
Multiple inheritanceYes — a class can implement manyNo — single base class only
FieldsNoYes
ConstructorsNoYes
Default implementationsYes (C# 8+)Yes
StateNoYes
Access modifiers on membersLimited (public by default)Full control
Use whenDefining a capability/contractSharing implementation between related types
C# Example Code
// Abstract class — shared state and logic
public abstract class Animal
{
    public string Name { get; }
    protected Animal(string name) => Name = name;

    public abstract void Speak(); // must override
    public virtual  void Sleep()  => Console.WriteLine($"{Name} sleeps."); // optional override
}

// Interface — capability, no shared state
public interface ITrainable
{
    void Train(string command);
}

public class Dog : Animal, ITrainable
{
    public Dog(string name) : base(name) { }

    public override void Speak() => Console.WriteLine($"{Name}: Woof!");
    public void Train(string command) => Console.WriteLine($"{Name} learned: {command}");
}

Checking Interface Implementation at Runtime

C# Example Code
object obj = new Dog("Rex");

// is pattern
if (obj is IAnimal animal)
    animal.Speak();

// as cast
ITrainable? trainable = obj as ITrainable;
trainable?.Train("Sit");