C# delegates can be used like function pointers. Assign it once and you don’t have to use an if over and over. But is the overhead of the delegate worth it? Today’s article puts it to the test to see if this a valid performance boost versus just using an if over and over. Read on to see if a delegate is worth your time.

Here’s a quick overview of the two approaches so you can see how to use delegates like function pointers:

// The 'if' approach
foreach (var cur in list)
{
    if (TestCondition)
    {
        // Do thing A...
    }
    else
    {
        // Do thing B...
    }
}
 
// The delegate approach using delegates as function pointers
delegate void Del();
void DoThingA()
{
}
void DoThingB()
{
}
void Foo()
{
    Del del;
    if (TestCondition)
    {
        del = DoThingA;
    }
    else
    {
        del = DoThingB;
    }
    foreach (var cur in list)
    {
        del(); // note: no 'if'
    }
}

Now let’s try out these two methods a bunch of times to see which one ends up being faster. Here’s the script:

using System;
using System.Diagnostics;
 
using UnityEngine;
 
public class TestScript : MonoBehaviour
{
	private string report = string.Empty;
 
	private const int NumIterations = 10000000;
 
	private Action del;
	private int count;
	private bool choice;
 
	void Start()
	{
		choice = true;
		del = AddOne;
		var stopwatch = new Stopwatch();
 
		stopwatch.Start();
		for (var i = 0; i < NumIterations; ++i)
		{
			Choose();
		}
		var ifTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var i = 0; i < NumIterations; ++i)
		{
			del();
		}
		var delegateTime = stopwatch.ElapsedMilliseconds;
 
		report = "Method,Time\n"
			+ "If," + ifTime + "\n"
			+ "Delegate," + delegateTime;
	}
 
	void Choose()
	{
		if (choice)
		{
			count++;
		}
		else
		{
			count--;
		}
	}
 
	void AddOne()
	{
		count++;
	}
 
	void SubtractOne()
	{
		count--;
	}
 
	void OnGUI()
	{
		GUI.TextArea(new Rect(0, 0, Screen.width, Screen.height), report);
	}
}

If you want to try out the test yourself, simply paste the above code into a TestScript.cs file in your Unity project’s Assets directory and attach it to the main camera game object in a new, empty project. Then build in non-development mode for 64-bit processors and run it windowed at 640×480 with fastest graphics. I ran it that way on this machine:

  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.10.4
  • Unity 5.1.2f1, Mac OS X Standalone, x86_64, non-development
  • 640×480, Fastest, Windowed

And here are the results I got:

Method Time
If 28
Delegate 48

Delegate Performance

Even after 10 million iterations the simple if approach is almost twice as fast as using a delegate as a function pointer. The delegate overhead—even in the fastest case—is simply too great compared to the lowly if. Instead, if you can, consider a third approach:

if (TestCondition)
{
    foreach (var cur in list)
    {
        // Do thing A...
    }
}
else
{
    foreach (var cur in list)
    {
        // Do thing B...
    }
}

This approach only does the if check once and doesn’t use delegates, so it should be the fastest.

Have you used delegates to gain performance? Found them losing you performance? Post about it in the comments!