Understanding C# Interfaces: Implementation, Inheritance, and Polymorphism

What Are Interfaces in C#?

An interface defines a contract that classes or structures must implement. It describes a set of related functionality that can belong to any class or structure. When a type implements an interface, it must provide concrete implementations for all interface members.

Interfaces are declared using the interface keyword and can contain methods, properties, events, and indexers in any combination.

Core Characteristics of Interfaces

Instance Creation Restrictions

Interfaces cannot be instantiated directly, similar to abstract classes. All interface members are implicitly abstract, meaning any non-abstract type implementing an interface must provide implementations for every member.

When implementing interface members, you have two approaches:

  • Explicit implementation: The implemented member is accessible only through an interface reference, not through a class instance.
  • Implicit implementation: The implemented member is publicly accessible and can be reached through both class and interface references.

Member Constraints

Interfaces cannot contain constants, fields, operators, instance constructors, destructors, or nested types. They also cannot include static members.

Access Modifiers

Interface members are automatically public and cannot have any access modifiers. This design choice exists because interfaces define communication contracts between objects. Marking methods as private or protected within an interface would defeat the purpose of establishing a universal contract.

Inheritance Rules

An interface can inherit from multiple other interfaces. Classes and structures can implement multiple interfaces simultaneously. However, interfaces cannot inherit from classes—this is a unidirectional relationship.

Implementation Strategies

Implicit Implementation

When a class implements a single interface, implicit implementation typically works well:

interface IDisplay
{
    void Show();
}

class ConsoleOutput : IDisplay
{
    public void Show()
    {
        Console.WriteLine("Displaying output.");
    }

    static void Main()
    {
        IDisplay display = new ConsoleOutput();
        display.Show();
    }
}

Explicit Implementation

When a class implements multiple interfaces containing members with identical signatures, explicit implementation becomes necessary:

interface IDisplay
{
    void Show();
}

interface ILogger
{
    void Show();
}

class Application : IDisplay, ILogger
{
    void IDisplay.Show()
    {
        Console.WriteLine("IDisplay implementation");
    }

    void ILogger.Show()
    {
        Console.WriteLine("ILogger implementation");
    }

    static void Main()
    {
        Application app = new Application();
        ((IDisplay)app).Show();
        ((ILogger)app).Show();
    }
}

Output:

IDisplay implementation
ILogger implementation

When explicit implementation is present for a member, any implicit implementation attempts are ignored by the compiler.

Interface Inheritance

Interface inheritance differs fundamentally from class inheritance:

Aspect Class Inheritance Interface Inheritance
Inheritance Type Implementation inheritance Contract inheritance only
Method Implementation Inherited with implementation Only method signatures inherited
Single vs Multiple Single inheritance only Multiple inheritance allowed

A derived interface inherits only member signatures from its base interfaces, not implementations. C# allows interface multiple inheritance, whereas class inheritance remains single inheritance.

interface IFormatter
{
    void Format();
}

interface ISerializable : IFormatter {}

class DataProcessor : ISerializable
{
    void IFormatter.Format()
    {
        Console.WriteLine("Formatting data.");
    }

    static void Main()
    {
        DataProcessor processor = new DataProcessor();
        ((ISerializable)processor).Format();
    }
}

Multiple interface inheritance uses comma separation:

interface IFirst
{
    void MethodA();
}

interface ISecond
{
    void MethodB();
}

interface ICombined : IFirst, ISecond {}

Method Invocation in Interface Implementations

Calling Abstract Methods

When an interface implementation calls an abstract method, polymorphism determines which concrete implementation executes:

interface IProcessor
{
    void Execute();
}

abstract class BaseProcessor : IProcessor
{
    public abstract void Process();

    void IProcessor.Execute()
    {
        Process();
    }
}

class Worker : BaseProcessor
{
    public override void Process()
    {
        Console.WriteLine("Processing complete.");
    }

    static void Main()
    {
        IProcessor processor = new Worker();
        processor.Execute();
    }
}

Execution flow: Execute() delegates to Process(), which resolves to Worker.Process() at runtime.

Output: Processing complete.

Calling Virtual Methods

The same polymorphic behavior applies when calling virtual methods:

interface IProcessor
{
    void Execute();
}

class BaseProcessor : IProcessor
{
    public virtual void Process()
    {
        Console.WriteLine("Base processor executing.");
    }

    void IProcessor.Execute()
    {
        Process();
    }
}

class Worker : BaseProcessor
{
    public override void Process()
    {
        Console.WriteLine("Worker processing override.");
    }

    static void Main()
    {
        IProcessor processor = new Worker();
        processor.Execute();
    }
}

Output: Worker processing override.

Method Hiding with the new Keyword

Using new instead of override creates method hiding rather than polymorphic overriding:

interface IProcessor
{
    void Execute();
}

class BaseProcessor : IProcessor
{
    public virtual void Process()
    {
        Console.WriteLine("Base implementation.");
    }

    void IProcessor.Execute()
    {
        Process();
    }
}

class Worker : BaseProcessor
{
    public new void Process()
    {
        Console.WriteLine("New worker implementation.");
    }

    static void Main()
    {
        Worker worker = new Worker();
        ((IProcessor)worker).Execute();
        worker.Process();
    }
}

Output:

Base implementation.
New worker implementation.

The new keyword hides the base implementation, so Execute() calls BaseProcessor.Process(), while direct calls on Worker invoke Worker.Process().

Interfaces vs Abstract Classes

Criteria Interfaces Abstract Classes
Primary Purpose Contract specification Shared behavior and state
Member Types Methods, properties, events, indexers only Can include all member types with implementations
Fields Not allowed Allowed
Access Modifiers All members implicitly public Can have private, protected, internal, or protected internal members
Implementation No method implementations (prior to C# 8.0) Can provide partial implementations
Inheritance Multiple interfaces supported Single inheritance only
Default Implementations C# 8.0+ supports default implementations Not applicable

When to use each:

  • Choose interfaces when you need to define contracts that multiple unrelated classes must implement.
  • Choose abstract classes when you need to provide common functionality with partial implementations for a class hierarchy.
  • Adding a new method to an interface breaks existing implementations, while adding to an abstract class automatically extends all derived classes.

Comparing Interfaces and Classes

Differences:

  • Interfaces cannot be instantiated directly
  • Interfaces contain no method implementations (except default implementations in C# 8.0+)
  • Interfaces support multiple inheritance; classes support single inheritance only
  • Class source code can span multiple files; interface declarations cannot

Similarities:

  • Both interfaces and classes can participate in inheritance hierarchies
  • Both can be inherited by structures and classes
  • Any non-abstract type inheriting from an interface must implement all members
  • Both can declare events, indexers, methods, and properties
  • Multiple interfaces can be implemented by a single class

Tags: C# Interface Object-Oriented Programming Inheritance Polymorphism

Posted on Sun, 07 Jun 2026 16:59:21 +0000 by crinkle