Saturday, June 27, 2026

C# Understanding Default Interface Method in Interface type and how to call it

In this post, you will understand about default interface method in an interface type. For this, look at the following code and answer this question: How to call default interface method Print of IContract interface in Program class?
interface IContract
{
    void Apply();
    void Print()
    {
        Console.WriteLine("Print Default implementation");
    }
}
class Implementer : IContract
{
    public void Apply()
    {
        Console.WriteLine("Implementer implemented Apply");
    }
    public void Print()
    {
        Console.WriteLine("Implementer implemented Print");
    }

    class Program
    {
        static void Main(string[] args)
        {
            Implementer implementer = new Implementer();
            implementer.Apply(); // Implementer implemented Apply
            implementer.Print(); // Implementer implemented Print
            IContract contract = implementer;
            contract.Print(); // Implementer implemented Print
        }
    }
}
Answer: Since default interface method Print is implemented in Implementer class, calling Print will invoke class implementation, not interface implementation. If you really want to invoke interface method implementation then class should not re-implement the default interface method implementation.
Soultion:
interface IContract
{
    void Apply();
    void Print()
    {
        Console.WriteLine("Print Default implementation");
    }
}
class Implementer : IContract
{
    public void Apply()
    {
        Console.WriteLine("Implementer implemented Apply");
    }

    class Program
    {
        static void Main(string[] args)
        {
            Implementer implementer = new Implementer();
            implementer.Apply(); // Implementer implemented Apply
            IContract contract = implementer;
            contract.Print(); // Print Default implementation
        }
    }
}
Since C# version 8 onward, method implementation is allowed in an interface type. The class implementing this interface cannot directly access this method. It means that class reference variable cannot directly acces this method.
implementer.Print(); // Invalid access

The compiler message is: "'Implementer' does not contain a definition for 'Print' and no accessible extension method 'Print' accepting a first argument of type 'Implementer' could be found (are you missing a using directive or an assembly reference?)"

But the interface reference variable pointing to the object of implementing class can access this method.
contract.Print(); // Print Default implementation

C# Evolution of Interface type over course of time

Interfaces in C# started as a pure contract type and gradually gained more capabilities across language versions. Here’s a timeline of the major additions.

C# Version Interface Feature Added Example
C# 1.0 (2002) Basic interfaces Method/property/event/indexer declarations
C# 2.0 Generic interfaces IEnumerable<T>
C# 3.0 No major interface changes
C# 4.0 Generic variance out, in
C# 5–7.x Minor improvements Expression-bodied members support
C# 8.0 Default interface implementations Method body inside interface
C# 8.0 Static members allowed (with bodies) Static helper methods
C# 8.0 Access modifiers inside interface private, protected, etc.
C# 11 Static abstract members Generic math
C# 11 Static virtual members Default static behavior

1. C# 1.0 — Interfaces as pure contracts

  • Only declarations were allowed.
  • No fields, no implementation.
  • abstract methods, properties, events and indexers
  • Implementation required in implementing class/struct

interface IShape
{
    void Draw();
    int Points { get; }
}
class Circle : IShape
{
    public int Points => 0;
    public void Draw()
    {
    }
}


2. C# 2.0 — Generic interfaces

  • Interfaces became type-safe.
  • Type parameter introduced with interface type and its members

interface IRepository<T>
{
    void Add(T item);
}

Example:
IEnumerable<int>
IComparer<string>


3. C# 4.0 — Variance (in, out)

  • Allowed covariance and contravariance.
  • in and out modifier with type parameter
  • The out modifier tells that the type parameter is return type
  • The in modifier tells that the type parameter is method parameter type
  • If in or out modifier is omitted  then type parameter can be (return type)/(parameter type)
Covariant (out) → return types:
interface IProducer<out T>
{
    T Create();
}

Contravariant (in) → parameter types:
interface IConsumer<in T>
{
    void Consume(T item);
}


4. C# 8.0 — Default Interface Methods (major change)
  • Interfaces could finally contain implementations.
  • This will be default implementation for implementers(class/struct)
interface ILogger
{
    void Log(string msg)
    {
        Console.WriteLine(msg);
    }
}
Implementers can inherit default behavior:
class FileLogger : ILogger
{
}

This helped version interfaces without breaking existing code.

5. C# 8.0 — Access modifiers in interfaces
Before C# 8:
interface ITest
{
void Show(); // implicitly public
}

After C# 8:
interface ITest
{
    public void Show()
    {
    }
    private void Helper()
    {
    }
}

👉public interface members became valid only once interfaces could contain implementations.

6. C# 8.0 — Static members in interfaces

interface IMath
{
    static int Add(int a, int b)
    {
        return a + b;
    }
}

Used like: IMath.Add(10, 20);

7. C# 11 — Static abstract members (very important)

  • Interfaces can require static members.
interface IAddable<T>
{
    static abstract T operator +(T a, T b);
}

Implementation:

struct Number : IAddable<Number>
{
    public int Value;
    public static Number operator +(Number a, Number b)
    => new Number { Value = a.Value + b.Value };
}

👉This enabled generic math.

8. C# 11 — Static virtual members
interface IExample
{
    static virtual int Value => 100;
}
Allows default static behavior.

Overall evolution

  1. Contract only(abstract declarations of method/property/event/indexer)
  2. Generic contracts(introduced type parameter T) 
  3. Variance support (in and out modifiers)
  4. Interfaces with behavior (default methods and access modifier with members)
  5. Static polymorphism (generic math)
So modern C# interfaces are much more powerful than the original “only abstract members” design.

 

Hot Topics