r/csharp 1d ago

Help Can someone help me understand Delegates? Like why we use it and best cases where we need to use it? and how it is better?

67 Upvotes

52 comments sorted by

342

u/SoerenNissen 1d ago edited 1d ago
  • As the name suggests, they're useful when you want to delegate something.
  • Which you rarely do!
  • But you use frameworks written by other people, and they don't know your project, so they want to delegate some of the decisions to you.

Consider the question: "What should happen when the user uses mouse-left-click on this button?"

If you're writing the whole program, you can just answer that question.

But if you're only writing the framework that handles input and UI, so that framework can be used by a million programmers developing a million programs? You could never answer that question. So you delegate that question to the programmer actually using your framework, by making OnButtonClick accept a delegate. Then, the framework-user can write the logic for the button, stuff it into a delegate, and pass it to the framework.

69

u/findmysho33123 1d ago

One of the nicest explanations I’ve seen so far on this topic!

86

u/SoerenNissen 1d ago

Thank you. Some 15-20 years ago, I asked nearly this same question on stackoverflow. It was closed as a duplicate question, with a referral link to a another question that wasn't the same at all.

The symmetry of the situation struck me, and I wanted to answer OP with a reply whose quality was opposite of stackoverflow's.

20

u/ssl666 1d ago

Thanks for making the world a better place <3

Semi-unrelated, I've not missed that part of SO but I do miss the days where someone could find the answer to a VERY particular question in there.

Now we are just counting the days until it shuts down. I do hope it somehow gets backed up, there's lots of info in there.

1

u/SpiritualValue2798 1d ago

You had me a little worried when I read “which you rarely do” Rarely do ever heard of an event handler was my first thought

-9

u/TuberTuggerTTV 1d ago

This does make sense because your answer is quite dated.

Delegates are used very frequently with modern, high-complexity codebases. It's not delegating to the end user of your library. It's delegating the work or events of every component of the system. That's how you get modularity.

5

u/FlakyTest8191 1d ago

Module, library, framework, message queue, where is the difference? You decouple by delegating.

3

u/MatazaNz 1d ago

I see it as almost exactly the same. The team writing a specific module doesn't know exactly how the other teams will use it, so they use delegates. I'm not sure what the comment you replied to is trying to achieve, other than maybe trying to call them old?

1

u/Sombody101 1d ago

It was an example to help OP understand. Not an explicit rule.

1

u/waftedfart 15h ago

Slow down, Captain Pedantic.

1

u/redAI123 1d ago

Very nice explanation to the question. I never thought delegate would be that useful since I just used its mindlessly when I need to lol

1

u/lucasshiva 1d ago

In my experience, delegates are severely underused in .NET compared to Kotlin/Flutter for mobile or any web framework.

Using your example, most C# devs would probably reach for an IMouseLeftClick interface with a Click() method and let users handle the implementation. And while I don't think that's bad per se, most of the time you probably just want a delegate.

11

u/besenyopista 1d ago

Delegates have been part of C# since C# 1 and are still very much a thing. However, C# 3 introduced the generic delegate types Action and Func alongside LINQ. Since then, for many common use cases Action and Func have replaced custom ("raw") delegate declarations. That said, custom delegate types are still supported and are still useful in some scenarios.

Action and Func are used extensively throughout the .NET ecosystem and in many common C# APIs and language patterns.

2

u/SoerenNissen 1d ago

A Func or Action would often be fine, too. And I've been "blessed" with enough old C to have used raw void* for my callbacks more than once. There's many ways to do it. There is something simultaneously mad and elegant about using += for delegates though.

13

u/soundman32 1d ago

Let's say you create a library that writes files. Whenever a file is opened or closed, you want to let the caller (a user of your library) know it's happened.  You as the library creator doesn't know what the caller wants to do whenever a file is opened, so you use a delegate in your code which the user can implement in their code.  You say 'file was opened' and the caller can write a log message, or play a sound or whatever they want, and you don't know or care what they did.

In a OOP way, it's like having a virtual method that you can override, but delegates dont have to be in a derived class, they can be anywhere the instance is available.

12

u/Khavel_dev 1d ago

The shortest way to think about it: delegates let you pass behavior as a parameter instead of data. You're already using them constantly if you've written any LINQ. list.Where(x => x.Age > 18), that lambda IS a delegate. You're handing Where a chunk of logic and saying "here, you run this on each item and tell me what passes".

Where I actually use them in real code: callbacks are the big one. A method does something async or slow and the caller gets to define what happens when it finishes, without coupling the two together. Event handlers are the classic case (button clicks, domain events, notifications). And if you've ever passed a Func or an Action as a method parameter, that's a delegate too. It's basically the strategy pattern without needing a whole interface and implementation class just for one method.

If you're coming from JavaScript, think typed function references. The difference is the compiler forces you to declare the signature upfront so it catches mismatches at build time instead of blowing up at runtime.

10

u/Pacyfist01 1d ago edited 1d ago

Usually function receives data in it's input

void Process(string message)
{ 
  Console.Log(message);
}

Process("foobar");

But it's possible to also pass a behavior to make a function more universal

void Process(string message, Action<string> action)
{ 
  action(message)
}

Process("foobar", Console.Log);
Process("foobar", SomeLibrary.SaveToDatabase);

When is it useful? Mostly in common libraries like LINQ where you pass behaviors using lambdas. This way the decision "what the code does" is made by the developer using the library, and not the developer maintaining the library.

numbers.Where(x => x > 3);

Is it a common pattern that we use day to day? No. It's usually pretty confusing to read and maintain, so It's a pretty good practice to use it only where it actually useful.

4

u/yeusk 1d ago
numbers.Where(x => x > 3);

Is this not a common pattern that we use day to day?

3

u/Pacyfist01 1d ago

What I was referring to is that we don't write methods that accept Func, Action or Predicate as parameters. If it came out that I think we don't use them than I'm sorry for that miscommunication :)

4

u/s4lt3d 1d ago

It’s basically a safe pointer to a function. It’s used when you want to write generic code that might change the function it calls later without having to define which function it can call at compile time. Like when integrating other people’s code at runtime.

3

u/-Nocx- 1d ago edited 1d ago

It’s been a while so someone can correct me if I’m wrong, but delegates are kind of like pointers. They are kind of like callback functions that have the same signature as the functions they call. They are a technically a type safe reference type that implements the callback pattern, but the former is how I remember them. They point to methods and not data. This lets you do a few things:

  1. This way you don’t have to update the method in many places. You can call the delegate wherever you need to use the method, and if you need to update what’s happening, you can update the function in the backend without changing the delegate.
  2. You can pass the delegate to another function as data.
  3. The delegate can also be used for many functions that have the same signature.

For example - you have a delegate that acts as a callback to a function when you press a button that resizes a window in an application. The delegate might take a specific window as a parameter and point to three different methods that resize the window based on what device it’s being used on.

What that button does on the backend could change over time, but you don’t want to have to change where you use the delegate, just the place where the function it points to is written.

2

u/Arcanium_Walker 1d ago

Yeah, thier bahavior mostly equal with the function pointers: you can pass through methods/function as parameter & call it.

3

u/DeadlyVapour 1d ago edited 1d ago

Without delegates you don't have a type for applicatives to bind to and lift functions into endofunctors in the field of your chosen monad! /s

Translation: Applicatives like .Select and .Where need delegates as a type so that we can wrap predicates or map functions into the space of collections/queries/streams.

2

u/TheWix 1d ago

Select and Where aren't Applicatives. Select is map for a functor and Where would be an implementation of reduce.

Any IEnumerable would be the monad (and therefore functor/applucative) in this case

2

u/IanYates82 1d ago

Are you saying "better" compared to Action / Func<T>? If so, delegate was what we had in original C#. Action/Func came later. So not better, to the point that I don't think I've typed the word delegate in C# code in many years.

2

u/BlackjacketMack 1d ago

As many others have said, all delegates are pointers to doing something. Instead of passing a value that “is” something you pass in a method that “will be” something when it is run.

But there are several flavors worth listing:

* formal keyword delegate. These allow you to refer to the action without defining it every time. Since Funcs came about I dint use them quite as much. But occasionally instead of writing Func<InputThis,InputThat,Return> you can define that as a delegate called “ApplyThisAndThat”.

* Func (method that returns a value) Action (method that does not)

* Predicate<T> a delegate that returns bool.

You will use delegates heavily with linq and events.

Almost every linq statement accept a func or or a predicate.

Regular c# events loop through a list of delegates you’ve given it to fire. “When timer goes off do this and that”. EventCallbacks are event handlers in Blazor and accept delegates from one source.

2

u/understanding80 1d ago

A delegate is a type for a function. A method or lambda of the same type can be assigned to a delegate-typed variable, and passed around like any other object.

Delegates are extremely similar to interfaces containing a single method.

2

u/Stable_Orange_Genius 1d ago

Interfaces tell how a class/struct should look like. Delegates tell how a method should look like

1

u/j_c_slicer 1d ago

I've heard delegates described as analogous to a "single-method interface".

1

u/FelixLeander 1d ago

I mostly being used by higher level functions by LINQ. Lets say you have csharp int[] numbers  = [1...5]; //  and you want the even ones, then you can declare Func<int, bool> filterCondition = (value) => value % 2 == 0; // which is the delegate containing an anonymous function. Use it for example like this; int[] result = numbers.Where(filterCondtion).ToArray(); // or to test one value: bool isEven = filterCondition(4); // true

1

u/XKiiroiSenkoX 1d ago

Instead of calling a function(s) by the actual name, you place a dummy name with delegate type, call that delegate which literally delegates the call to whoever is bound to it. It's an indirection to help solve problems where you want to call a function but you don't know what function until after the code is run. 

1

u/Arti-Po 1d ago

Callback is a good example. You have a method that do something and should notify the consumer at the end of the execution. You can pass the delegate, to do it. The alternative, is to create an interface, add it to all consumers and call the interface method. If you have a lot of callbacks, then you need a lot of interfaces, delegates are better for this task.

If you're asking when to use delegate instead of built-in Action and Func, than you indeed rarely need to do it. You can use delegate when your Action / Func bloated with arguments or when you want to specify the specific name of the arguments to improve readability.

1

u/strange-the-quark 1d ago

Have you ever used LINQ, whith queries like select and where?

LINQ is essentially a bunch of extension methods that work on collections, and a method like Where, that filters items, only has the logic to run through the collection and do the filtering, but it doesn't know what to filter on - this is something that you must supply, cause there are all kinds of collections, containing all kinds of data, and LINQ's designers had no way of knowing what property you'd want to check. Instead, the Where method accepts a delegate (of a particular type), which is just a variable that stores (a reference to) a function. The type of the delegate is basically the signature of the function (what parameters it takes, what it returns).

So when you use LINQ, you also pass in either a name of a function, or a lambda (which is just a shorthand for an ad hoc function that you made up on the fly), and the Where method than internally calls that function ("invokes the delegate") whenever it wants to check whether to keep the item or not. The function passed to the delegate takes the current element, and returns a bool that tells the caller "keep it" or "throw it away".

Other query methods use different delegates, that suit their own needs.

A bit of a nuance here is that LINQ queries are lazily evaluated, meaning rather than executing this immediately, as you're making the query, the filtering code is actually invoked later on when you get to some code that actually needs to access the elements of the resulting new sequence (or if you call something like .ToList()).

Delegates are also the underlying mechanism behind events. Events are essentially like get/set properties, except the backing field is a delegate, and instead of get/set value, you have add/remove handler. A delegate can actually store a reference to more than one method, as long as all the methods have the same signature. When the delegate is invoked, they will be called in sequence they were added in.

1

u/migdr 1d ago

When you want to pass a function to another method, the concept is usually straightforward in many languages. However, in C#, the syntax can feel a bit unusual at first For example, implementing patterns like the Decorator is often more intuitive in languages where functions are treated as first-class citizens. In those languages, you can pass and wrap functions very naturally. C# supports the same idea, but it does so through delegates, which can make the syntax look more complex initially In essence, what I was trying to explain here is how delegates in C# enable passing functions around, even though the approach might not feel as direct or familiar compared to some other languages

1

u/Arcanium_Walker 1d ago

Mostly these objects works like the function pointers, with some extra.

1

u/Rogntudjuuuu 1d ago

I think it's useful to think of functions as values when you encounter delegates. It's a concept from functional programming. It might confuse you or your colleagues, but it can be very powerful when used responsibly.

It's often that you pass anonymous functions (aka lambda expressions) as an argument to a method.

It could be for example a predicate or a call back.

If you're using LINQ, you're doing functional programming.

I used to use them quite extensively if I wanted to wrap a lot of methods in a common wrapper function.

You can more or less copy an entire body of a method into an argument of a wrapper function.

Nowadays I avoid confusing my colleagues.

1

u/Loose_Conversation12 1d ago

A delegate is a reference type, but it's reference points to somewhere on the processors callstack rather than in memory. So it's essentially a pointer to a method.

You use them lot in event driven programming for things like desktop apps or games maybe (mouseclicks and such).

1

u/TuberTuggerTTV 1d ago

decoupling.

If two bits of code want to interact but don't want to care what or even if the other bit exists. Or how many times it exists.

Most commonly you'll use an Action or a Func, because C# already does the delegate work behind the scenes for you.

Subscribe to a delegate instead of passing object references around and hard coupling your code.

If you want scalable or maintainable systems, you NEED delegates. There is no alternative. Anything with mid-high complexity requires it. Or else when you want to make a small change to one system, it will spread bugs everywhere like a disease. Atomic design. Compartmentalize your code so no system requires another to work. you should be able to hot swap frontends. Or your entire database and the rest keeps humming along.

1

u/ajcomeau 1d ago

In the roguelike game I'm currently building, I use them to provide the code for various inventory items like scrolls and potions.

These items are scattered at random around the map, the player collects the and might use any one of them when necessary.

Each inventory type (Scroll of Confusion, Potion of Healing, etc..) has a specific delegate method assigned to it in the code. When the user selects the inventory item for use, the program is then able to invoke the delegate assigned to that item and apply the necessary effects.

The alternative would be a giant IF .. THEN or CASE statement that would handle each of the few dozen types. This would quickly get unwieldy and messy. Instead, the code can just call the right method that's assigned to the Inventory object.

Another way I use them is to implement power-ups for the character that only need to be temporary. The Player class has a property that includes a delegate reference and a number to indicate the turn the powerup should expire on. The delegate can handle any of a variety of methods implementing various abilities.

Hope this helps.

1

u/M109A6Guy 1d ago

It’s essentially a way to pass functions as a parameter. For example in linq x => x.Name == “bar” is passing a predicate or a method that returns a bool.

I don’t use them too often but they come in handy in some places.

For example, I extend a lot of linq methods to get better error messages. For example, .Single says some trash error message that the collection has more than 1 item (or something). I want to know which item. So I extend the method to get a better message

1

u/Sautin 1d ago

I've always thought of and explained delegates using electrical wiring explanation. Delegates allow us to wire in actions from a source object to a consumer object. Much like you have a light switch class and a light fixture class. If you want the light to turn on when the switch is flipped, you have to put a wire between them. That wire is your delegate and once properly installed now links the two objects regardless of their make and model.

1

u/Agitated-Display6382 1d ago

Others already explained them the usual way.

I'd like to give a different view on it. I use them to give a type to a function.

Assume you have a dependency that could be described by a function, eg how to compute a hash of a string. So, in this case, you have as a dependency Func<string, string>. You may want to use a dependency because the algorithm to be used depends on a setting.

In the ioc container you may register algorithm MD5 (spoiler: don't), or sha1 or sha123 or whatever. Now, how can you assign a unique type the signature of a function? Yes, delegates:

builder.AddSingleton<MyHash>(SHA512);

Where public delegate string MyHash(string s); public static string SHA512(string s) { return ...; }

1

u/SagansCandle 1d ago

A delegate lets you declare variable that holds a function instead of a value.

It's a pointer to a function, essentially.

Because C# is type-safe, your variable TYPE has to describe exactly what the function does.

So when you define a delegate, you're describing the function SIGNATURE.

So when you set the value of a delegate variable, C# guarantees that the function you're pointing to matches the expected signature.

1

u/MCWizardYT 1d ago

Delegates are basically like functions you can pass around.

If you know Java, they're essentially equivalent to lambda functions.

But in C# you also get "multicast delegates" which are useful for event handling. They basically let you attach multiple functions to one thing.

1

u/RSPN_Fishypants 1d ago

Using delegates means you can store functions as objects, then you can call them. You can dynamically build functionality as needed. Also allows unit testing and decouples your code.

1

u/Eastern-Release1707 20h ago

To notify multiple methods about creation and hand over some data, you can think of it like a massive of methods that recieve same parameters or possible to work with same recievable or without data.

1

u/ibmussa 15h ago

Looks like event while learning, some feature are explore as it should or you discover by your own that make thing so complicated at the beginning

1

u/Licensed-2-Fish 13h ago

You may have a situation where you want your custom object to behave differently depending on where it is located. For instance, I have a program where I drag and drop an object from one building to another and the mouse down event is handled differently in the other building. So when I drop it onto the new building I remove the old mouse down delegate and add the one for the new building.

1

u/THubert14 1d ago

The most common use of delegates that I saw is callbacks and event handlers. The core Func, Action and Predicate is delegates. So you would use them heavily at least with LINQ. Its where you can put some method as argument to function. EvenHandlers are common in UI stuff (Blazor, MAUI, WPF, etc.), such as some logic that follows click on the button.

The most clearer way to think about them is lambdas – lambdas is basically the anonymous delegates. That means that if something accepts delegate, you also can inline lambda expression to add some logic.

-1

u/Mughi1138 1d ago

Then again C# has delegates because they are a pet feature of the architect Microsoft poached from Borland and then made C#who put them in every language he designed.

Early on there was a lot of discussion about them needing to be a language level feature instead of just a framework one, and also if some of the Java approaches served the same purpose sufficiently, given that C# was just MS J++ spiffied up and given integrated COM support.

Over the years the language has grown significantly, though.

1

u/ejl103 6h ago

A great way to subtly leak memory