Programming C# — What are Delegates?

Thomas Steffen
4 min readSep 13, 2023

--

Delegates allow you to store a function inside a variable. To get more detailed, a delegate is a type that represents references to methods with a particular parameter list and return type. Essentially, a delegate allows you to treat methods as objects, enabling you to pass methods as parameters to other methods, store them in variables, and invoke them dynamically at runtime.

Delegates provide a type-safe way to encapsulate a method. This means that the delegate type specifies the method’s parameter types and return type. You can’t assign a delegate of one type to another delegate with a different method signature.

To declare a delegate, you define its signature, which includes the return type and parameters. For example:

delegate int MyDelegate(int x, int y);

You can create an instance of a delegate by associating it with a method that matches its signature:

MyDelegate myDelegate = Add; 
// 'Add' is a method with the same signature

To invoke a delegate, you treat it like a method and call it with the appropriate arguments:

int result = myDelegate(5, 3); 
// Calls the 'Add' method through the delegate

Delegates can be combined using the += operator to create multicast delegates. A multicast delegate can reference multiple methods, and when invoked, it calls all the referenced methods in order:

MyDelegate multiDelegate = Add;
multiDelegate += Subtract;
int result = multiDelegate(5, 3);
// Calls both 'Add' and 'Subtract'

C# provides several built-in delegate types in the System namespace, such as Action, Func, and various EventHandler types, which simplify working with delegates for common scenarios.

These built-in delegates live in a place called the System namespace. Think of them as pre-designed tools you can find in a toolbox.

Action is like a tool you can use when you want to do something but don’t need any specific information back. It’s just for getting a job done.

Func is like a tool for when you need to do something and get some information back. It helps you with tasks that have results.

EventHandler is great when you want to handle events, like when a button is clicked in a program. They make it easier to work with those kinds of situations.

So, these built-in delegates are like pre-made tools that C# gives you to make your programming tasks easier.

Why use delegates?

Delegates are often used for callback mechanisms, event handling, and implementing the observer pattern. They allow you to decouple the caller from the specific methods it invokes.

Callback” — You’re asking a friend for help with a problem, but you don’t know exactly how your friend will solve it. So, you give your friend a special phone number (the delegate), and you say, “When you figure it out, call this number, and I’ll do something with the answer.” This way, you don’t need to know all the details of how your friend will help you; you just know you’ll get the answer when it’s ready.

Event handling” — Imagine you’re hosting a big party, and you want to know when someone arrives at the party. You can give out special party invitations (the delegate), and you tell your friends, “When you arrive at the party, give me your invitation back.” This way, you can keep track of who’s at the party without having to watch the door all the time.

“Observer pattern” — This is like having a weather app. The app doesn’t know the weather; it asks a weather station for updates. If the weather changes, the station sends a message to the app. Delegates are like the messages that help different parts of a program talk to each other without knowing too much about what the other parts are doing.

In simple terms, delegates are like tools that help different parts of a program work together without needing to know all the details about what each part is doing. They’re handy for callbacks, event handling (like our party), and making different parts of a program talk to each other (like the weather app).

I also wanted to touch on Lambda’s use in Delegates:

public delegate void MyDelegate();
/*we declare a delegate named MyDelegate. A delegate is like a blueprint
for a method. It defines the structure of a method that can be later
assigned to point to other methods with the same structure.*/


private MyDelegate myDelegateFunction;
/*We declare a private instance variable myDelegateFunction of
type MyDelegate. This variable will be used to hold a reference
to a method that matches the signature defined by MyDelegate.*/

private void Start()
{
myDelegateFunction = () => { Debug.Log("Lambda Expression"); };
/*myDelegateFunction now holds a reference to this lambda expression.
You can later invoke myDelegateFunction(), and it will execute the code
within the lambda expression, which is the logging of "Lambda Expression"
to the console.*/
}
  • () => { Debug.Log("Lambda Expression"); } is a lambda expression.
  • () => is the lambda operator, indicating that this is a lambda expression.
  • { Debug.Log("Lambda Expression"); } is the body of the lambda expression, containing the code to be executed when the delegate is invoked.

In summary, this code demonstrates the use of a delegate (MyDelegate) and assigns a lambda expression to it. When the delegate is invoked, it executes the code defined in the lama expression. This provides a way to store and call functions dynamically, which can be useful for various programming scenarios.

I will write another article specifically on Lambda, as it can get a little more complex. But I wanted to include it in with Delegates, as it is quite useful.

Lamb Duh

--

--

Thomas Steffen

I am Virtual Reality Developer, UI Systems, and general programmer with a passion for Unity software development.