performance
delegates
methods
programming
optimization

Performance of calling delegates vs methods

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In .NET, a direct method call is usually faster than invoking a delegate, but the difference is often much smaller than people expect. The important question is not "which is faster in theory," but whether the delegate overhead matters in the code path you care about. In most application code it does not; in extremely hot loops it can.

What a Direct Method Call Buys You

A normal instance or static method call gives the runtime the simplest possible call path. The JIT can sometimes inline the target method, remove call overhead, and optimize surrounding code more aggressively.

csharp
1using System;
2
3class Calculator
4{
5    public int AddOne(int value)
6    {
7        return value + 1;
8    }
9}
10
11var calc = new Calculator();
12Console.WriteLine(calc.AddOne(41));

For a tiny method like AddOne, inlining is plausible in optimized builds. That matters because once the call disappears, the runtime can optimize the loop around it as well.

What a Delegate Adds

A delegate is an object that stores a callable target. That indirection is what makes delegates flexible, but it also introduces extra work:

  • the runtime must invoke through the delegate wrapper
  • inlining opportunities are more limited
  • multicast delegates may call more than one target
csharp
1using System;
2
3class Calculator
4{
5    public int AddOne(int value)
6    {
7        return value + 1;
8    }
9}
10
11var calc = new Calculator();
12Func<int, int> op = calc.AddOne;
13Console.WriteLine(op(41));

This is still fast. It is just typically a little slower than the direct call.

Measuring It Properly

If you care about the difference, benchmark it instead of guessing. A naive stopwatch test inside a debug build is not reliable. Use BenchmarkDotNet or a similarly careful harness.

csharp
1using BenchmarkDotNet.Attributes;
2using BenchmarkDotNet.Running;
3using System;
4
5public class CallBenchmarks
6{
7    private readonly Calculator _calculator = new Calculator();
8    private readonly Func<int, int> _delegate;
9
10    public CallBenchmarks()
11    {
12        _delegate = _calculator.AddOne;
13    }
14
15    [Benchmark]
16    public int DirectMethod()
17    {
18        return _calculator.AddOne(123);
19    }
20
21    [Benchmark]
22    public int DelegateCall()
23    {
24        return _delegate(123);
25    }
26}
27
28public class Calculator
29{
30    public int AddOne(int value) => value + 1;
31}
32
33BenchmarkRunner.Run<CallBenchmarks>();

Typical results show direct calls winning, but not by an order of magnitude. The exact numbers depend on runtime version, hardware, JIT behavior, and whether the method can be inlined.

Where the Overhead Actually Matters

The delegate penalty matters only when the call itself is the dominant cost. That usually means:

  • the target operation is tiny
  • the call happens millions or billions of times
  • the code runs inside a tight loop

For example:

csharp
1using System;
2
3class Calculator
4{
5    public int AddOne(int value) => value + 1;
6}
7
8var calc = new Calculator();
9Func<int, int> op = calc.AddOne;
10
11int total = 0;
12for (int i = 0; i < 10_000_000; i++)
13{
14    total += op(i);
15}
16
17Console.WriteLine(total);

In a loop like that, even small per-call overhead accumulates. In contrast, if the delegate is wrapping database access, file I/O, JSON parsing, or a network request, the dispatch cost is irrelevant.

Why Delegates Are Still Worth Using

Delegates exist because they solve real design problems:

  • callbacks
  • event handlers
  • strategy injection
  • LINQ-style higher-order functions
  • pipelines that pass behavior around

Those are architectural benefits, not performance accidents.

If delegates make the code more composable or more testable, that is often the right trade. Eliminating them solely for micro-performance can make the code worse while producing no visible user benefit.

A Special Case: Multicast Delegates

Not all delegate invocations cost the same. A multicast delegate stores an invocation list and calls each target in order.

csharp
1using System;
2
3Action handler = null;
4handler += () => Console.WriteLine("first");
5handler += () => Console.WriteLine("second");
6
7handler();

That is fundamentally more work than calling a single method, because there may be several methods behind the delegate. If you benchmark delegates, be clear whether you are measuring a single-cast or multicast case.

A Practical Rule of Thumb

Use direct methods when:

  • you are in a genuinely hot path
  • the target work is tiny
  • profiling shows dispatch overhead is measurable

Use delegates freely when:

  • you need indirection or callbacks
  • you are expressing pluggable behavior
  • the real work dominates the call overhead anyway

The correct order is design first, profile second, optimize third.

Common Pitfalls

  • Assuming delegate overhead is huge in normal application code. It usually is not.
  • Benchmarking in debug mode or with a poor harness. Use a real microbenchmark tool.
  • Ignoring JIT inlining when comparing direct calls to delegate calls. Inlining can change the result significantly.
  • Treating multicast and single-cast delegates as the same performance case. They are not.
  • Removing delegates for "speed" without profiling. That often hurts design with no user-visible gain.

Summary

  • Direct method calls are usually faster than delegate invocations.
  • The gap is often small unless the call is in a very hot, tiny loop.
  • Delegates add indirection and may reduce inlining opportunities.
  • Multicast delegates cost more than single-target delegates.
  • Profile before rewriting architecture around micro-performance assumptions.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.