Skip to content
AgileLogics
6 min read

Interfaces

Prerequisites: Inheritance

An interface lists members that a class promises to provide, without saying how. A class can inherit from only one base class, but can implement many interfaces.

Public Interface IShape
    ReadOnly Property Name As String
    Function Area() As Double
End Interface

Public Class Circle
    Implements IShape

    Private ReadOnly radius As Double

    Public Sub New(radius As Double)
        Me.radius = radius
    End Sub

    Public ReadOnly Property Name As String Implements IShape.Name
        Get
            Return "circle"
        End Get
    End Property

    Public Function Area() As Double Implements IShape.Area
        Return Math.PI * radius * radius
    End Function
End Class

Public Class Square
    Implements IShape

    Public Property Side As Double

    Public ReadOnly Property Name As String Implements IShape.Name
        Get
            Return "square"
        End Get
    End Property

    Public Function Area() As Double Implements IShape.Area
        Return Side * Side
    End Function
End Class

Module Program
    Sub PrintAll(shapes As IEnumerable(Of IShape))
        For Each s In shapes
            Console.WriteLine($"{s.Name}: {s.Area():F2}")
        Next
    End Sub

    Sub Main()
        PrintAll({New Circle(1), New Square With {.Side = 2}})
    End Sub
End Module
circle: 3.14
square: 4.00
  • Interface names start with I by convention.
  • VB is explicit: each member says which interface member it implements with Implements IShape.Area. The class member can even have a different name.
  • PrintAll accepts anything that implements IShape — it doesn't care about the concrete class.

Built-in interfaces

Implementing standard .NET interfaces plugs your classes into the framework. IComparable(Of T) makes objects sortable:

Public Class Player
    Implements IComparable(Of Player)

    Public Property Name As String
    Public Property Score As Integer

    Public Function CompareTo(other As Player) As Integer Implements IComparable(Of Player).CompareTo
        Return other.Score.CompareTo(Score)    ' highest score first
    End Function
End Class

Module Program
    Sub Main()
        Dim players As New List(Of Player) From {
            New Player With {.Name = "Ada", .Score = 80},
            New Player With {.Name = "Grace", .Score = 95},
            New Player With {.Name = "Linus", .Score = 70}
        }
        players.Sort()
        For Each p In players
            Console.WriteLine($"{p.Name} {p.Score}")
        Next
    End Sub
End Module
Grace 95
Ada 80
Linus 70

Other common ones: IDisposable (release resources with Using), IEquatable(Of T) (value equality), and IEnumerable(Of T) (work with For Each and LINQ).

Interfaces for testable code

Depending on an interface instead of a concrete class lets you swap implementations — for example, a fake clock in tests:

Public Interface IClock
    Function Now() As Date
End Interface

Public Class FixedClock
    Implements IClock
    Public Function Now() As Date Implements IClock.Now
        Return New Date(2025, 12, 24, 18, 0, 0)
    End Function
End Class

Public Class Greeter
    Private ReadOnly clock As IClock
    Public Sub New(clock As IClock)
        Me.clock = clock
    End Sub
    Public Function Greet() As String
        Return If(clock.Now().Hour < 12, "Good morning", "Good evening")
    End Function
End Class

Module Program
    Sub Main()
        Console.WriteLine(New Greeter(New FixedClock()).Greet())
    End Sub
End Module
Good evening

Passing dependencies in through the constructor like this is called dependency injection; ASP.NET Core and most modern .NET frameworks are built around it.