Skip to content
AgileLogics
6 min read

Exception Handling

Prerequisites: Classes and objects

When something goes wrong at run time, .NET throws an exception. You handle it with Try ... Catch ... Finally ... End Try.

Module Program
    Function SafeDivide(a As Integer, b As Integer) As Integer?
        Try
            Return a \ b
        Catch ex As DivideByZeroException
            Console.WriteLine($"  ({ex.Message})")
            Return Nothing
        End Try
    End Function

    Sub Main()
        Console.WriteLine(SafeDivide(10, 2))
        Console.WriteLine(SafeDivide(10, 0).HasValue)
    End Sub
End Module
5
  (Attempted to divide by zero.)
False

Integer? is a nullable Integer that can also be Nothing (see Nullable Values and Nothing later in this level).

Several Catch blocks and Finally

Module Program
    Sub Process(text As String)
        Try
            Dim n = Integer.Parse(text)
            Console.WriteLine($"  100 / {n} = {100 \ n}")
        Catch ex As FormatException
            Console.WriteLine($"  not a number: '{text}'")
        Catch ex As DivideByZeroException
            Console.WriteLine("  can't divide by zero")
        Catch ex As Exception
            Console.WriteLine($"  unexpected: {ex.Message}")
        Finally
            Console.WriteLine($"  finished '{text}'")
        End Try
    End Sub

    Sub Main()
        For Each entry In {"4", "abc", "0"}
            Process(entry)
        Next
    End Sub
End Module
  100 / 4 = 25
  finished '4'
  not a number: 'abc'
  finished 'abc'
  can't divide by zero
  finished '0'
  • Catch blocks are tested in order — put specific exceptions first and Exception (which catches everything) last.
  • Finally always runs, whether or not an exception happened — use it for cleanup.
  • Catch ex As Exception When condition adds a filter.

Throwing exceptions

Public Class InsufficientFundsException
    Inherits Exception

    Public ReadOnly Property Shortfall As Decimal

    Public Sub New(shortfall As Decimal)
        MyBase.New($"Insufficient funds: short by {shortfall}.")
        Me.Shortfall = shortfall
    End Sub
End Class

Module Program
    Function Withdraw(balance As Decimal, amount As Decimal) As Decimal
        If amount <= 0 Then Throw New ArgumentOutOfRangeException(NameOf(amount), "Amount must be positive.")
        If amount > balance Then Throw New InsufficientFundsException(amount - balance)
        Return balance - amount
    End Function

    Sub Main()
        Try
            Console.WriteLine(Withdraw(100D, 30D))
            Console.WriteLine(Withdraw(100D, 250D))
        Catch ex As InsufficientFundsException
            Console.WriteLine($"{ex.Message} (Shortfall = {ex.Shortfall})")
        End Try

        Try
            Withdraw(100D, -5D)
        Catch ex As ArgumentOutOfRangeException
            Console.WriteLine(ex.ParamName)
        End Try
    End Sub
End Module
70
Insufficient funds: short by 150. (Shortfall = 150)
amount
  • Throw New SomeException(...) raises an exception.
  • Custom exceptions inherit from Exception and can carry extra data.
  • NameOf(amount) gives "amount" as a string that stays correct if you rename the parameter.
  • Inside a Catch, a bare Throw rethrows the current exception without losing its stack trace.

Using: automatic cleanup

Objects that hold resources (files, connections) implement IDisposable. A Using block disposes them when it ends — even if an exception occurs:

Public Class Resource
    Implements IDisposable
    Public Sub New()
        Console.WriteLine("opened")
    End Sub
    Public Sub Dispose() Implements IDisposable.Dispose
        Console.WriteLine("closed")
    End Sub
End Class

Module Program
    Sub Main()
        Try
            Using r As New Resource()
                Console.WriteLine("working")
                Throw New InvalidOperationException("something broke")
            End Using
        Catch ex As InvalidOperationException
            Console.WriteLine($"caught: {ex.Message}")
        End Try
    End Sub
End Module
opened
working
closed
caught: something broke

On Error GoTo (legacy)

VB6 and VBA handle errors with On Error GoTo Handler and On Error Resume Next. VB.NET still accepts them for compatibility, but they can't be mixed with Try in the same procedure. Always use Try/Catch in new code — From VB6 to VB.NET in Level 3 shows how to convert.

Common mistakes

  • Empty Catch blocks that swallow errors silently.
  • Using exceptions for normal decisions: check with TryParse, File.Exists, or ContainsKey first when failure is expected.