Search Unity

info delegate

Discussion in 'Scripting' started by Bolt, Oct 12, 2017.

  1. Bolt

    Bolt

    Joined:
    Dec 15, 2012
    Posts:
    296
    in what situations can I use delegates? what exactly do they serve?
     
  2. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    So far I've been using it as custom events to not involve UnityEvents as long as the functionality does not need to be exposed in the inspector. Also have been recently using it to store functions in variables, alternatively as a parameter to other functions. Pretty sure others with a proper computer science and/or engineering background will fill in more, but just my personal experience using delegates so far.
     
  3. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    @Laperen pretty much covered how I use them, as well. They are "pointers to functions". Events also wrap around delegates, making them more secure. It's easy to google to term/topic. :)
    Every delegate is also a multicast delegate, and to it you can add/remove (1 or more) methods.
    Sorting is a classic example of when a delegate can be used (/passed). The method uses the method you pass it to sort, for example.
     
  4. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    There are lots of situtation in which they're useful.

    They more or less allow to store "functions" (it's little bit more complex - but it's enough for now). That is, you can have some kind of "agreement / contract" about a single invokable method, pretty similar to the purpose of an interface - but for a single method instead.

    For example, in Java you often used to solve this by exactly that - listener interfaces. Their purpose was usually to be implement by anything that is a potential re-actor to some kind of invocation. If you wanted to allow more listeners, you'd take a collection of that listener's type.

    Delegates solve the latter by automatically turning into multi-delegates - pretty useful.

    You often use them to inverse call-behaviour, delayed calls (callbacks) and similar stuff. Nothing that could not be modelled using types, but hey - it's sugar. Less types in your project.

    So you don't need a specific type to invoke some method, only a matching function signature (including return value).
    This is pretty neat.

    But there's more to that. C# allows you to use them with the "event" modifier.
    The event modifier constraints direct invokation to the declaring type - not even subtypes. Of course you can raise them indirectly.

    The modifier can be implemented explicitly - just like properties. By default, an event will use a backing-delegate and adds/removes subscribers to that backing-delegate and (afaik) uses a lock to do that as well (edit* this has changed slightly with C# 4 according to quick research)

    You can re-define this behaviour by explicitly defining the add/remove accessors yourself. Also pretty neat, but the default is probably what you're gonna use the most anyway.

    Once again, this is often used (as the name "event" suggests) in situations that look like:

    ObjectA: I can tell about anything exciting / useful / important that happens
    ObjectB: Oh great! Subscribed!

    Later in your application, ObjectA can raise the event and every subscriber can execute its logic.
     
    Last edited: Oct 12, 2017
  5. Pharaoh_

    Pharaoh_

    Joined:
    Feb 13, 2014
    Posts:
    36
    For someone who does not understand delegates, you had better start with an example than using abstract terms or jargon, as they add further to the confusion. Talking about multi-delegates when the author does not even understand what a delegate is, backing-delegate, listeners, etc., is quite much in my humble opinion.

    A delegate is pretty much an event and an action at the same time. Assume you have three animals whose timer expired and they want to eat. However, eating is reliant on a human to feed them in the first place. When the animal wants to eat, they alert the human to feed them. This process of alerting/requesting is the core purpose of a delegate.

    In slightly more technical terms, Animal is a class and it has a method called Eat().
    Inside Eat, you have:

    Code (CSharp):
    1.  
    2. public delegate void feedingRequest (Vector3 location);
    3.  
    4. public feedingRequest onFeedRequest;
    5.  
    6. void Eat () {
    7. Vector3 animalPosition = transform.position;
    8. if (!thereIsFoodAround (animalPosition)) {
    9.   if (onFeedRequest != null) {
    10.    onFeedRequest (animalPosition);
    11. }
    12. }
    13. }
    This function checks whether there is food around from a separate function (e.g., in a radius of 5 metric units). If not, it asks a human to toss some food at the animal's location.

    As you can see you do not make a direct reference to the Human class. The Animal class knows nothing about the Human class. All it knows is that it needs to eat and there is shortage of food. It could be fed by a machine as well, or another entity. As such, you could have a Machine class as well, which can also feed the animals. What you do is you subscribe to the delegate that lives inside the Animal class (onFeedRequest), in order to "listen" to their needs:

    Code (CSharp):
    1. public class Human {
    2.  
    3. public Transform foodPrefab;
    4.  
    5. void Feed (Vector3 position) {
    6. GameObject.Instantiate (foodPrefab, position, Quaternion.identity);
    7. }
    8.  
    9. void AnimalFeedingBehavior () {
    10. foreach (Animal a in Stable.getAnimals) {
    11.   a.onFeedRequest += Feed;
    12. }
    13. }
    14.  
    15. }
    If you also have a Machine, you can also listen to the animal's needs, even if the Human has also registered. This means that you will have two subscribers to your onFeedRequest delegate. As such, when the animal in the Eat() method invokes the onFeedRequest, it alerts both the Human and the Machine instances who have subscribed.
     
    Last edited: Oct 12, 2017
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824

    Well, there are books and better resources than any post here that explain this in-depth for beginners.
    My intention was to give a quick overview about what they are (kind of). Followed by a comparison with an alternative way to implement this using interfaces. By that, you can extract the idea behind it.

    The next paragraph was about multiple entities that are interested in an event - how this can be implemented using interfaces and that a similar effect is automatically done by the delegates (which are then called multi(cast)-delegates). So the explanation is actually right there, if you read carefully.

    I expect someone to just search or ask about further information when something (or some term) is unclear, instead of giving the illusion that one snippet is everything you need to know - because it isn't.

    It's a complex topic, you cannot explain it in short and if you try - you either use technical terms for further look-up to keep it short or you only post half of it by leaving out important information.

    For instance, your examples are quite misleading. You usually don't want to have raw delegates as events, because everyone can delete, raise and assign/replace them. You want them to be encapsulated using the event modifier, otherwise you could consider this a flaw in the design.
     
    Last edited: Oct 12, 2017