Advantages of using delegates?

2019-01-21 21:31发布

问题:

I'm looking to implement the Observer pattern in VB.NET or C# or some other first-class .NET language. I've heard that delegates can be used for this, but can't figure out why they would be preferred over plain old interfaces implemented on observers. So,

  • Why should I use delegates instead of defining my own interfaces and passing around references to objects implementing them?
  • Why might I want to avoid using delegates, and go with good ol'-fashioned interfaces?

回答1:

When you can directly call a method, you don't need a delegate.

A delegate is useful when the code calling the method doesn't know/care what the method it's calling is -- for example, you might invoke a long-running task and pass it a delegate to a callback method that the task can use to send notifications about its status.

Here is a (very silly) code sample:

enum TaskStatus
{
   Started,
   StillProcessing,
   Finished
}

delegate void CallbackDelegate(Task t, TaskStatus status);

class Task
{
    public void Start(CallbackDelegate callback)
    {
        callback(this, TaskStatus.Started);

        // calculate PI to 1 billion digits
        for (...)
        {
            callback(this, TaskStatus.StillProcessing);
        }

        callback(this, TaskStatus.Finished);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Task t = new Task();
        t.Start(new CallbackDelegate(MyCallbackMethod));
    }

    static void MyCallbackMethod(Task t, TaskStatus status)
    {
        Console.WriteLine("The task status is {0}", status);
    }
}

As you can see, the Task class doesn't know or care that -- in this case -- the delegate is to a method that prints the status of the task to the console. The method could equally well send the status over a network connection to another computer. Etc.



回答2:

You're an O/S, and I'm an application. I want to tell you to call one of my methods when you detect something happening. To do that, I pass you a delegate to the method of mine which I want you to call. I don't call that method of mine myself, because I want you to call it when you detect the something. You don't call my method directly because you don't know (at your compile-time) that the method exists (I wasn't even written when you were built); instead, you call whichever method is specified by the delegate which you receive at run-time.



回答3:

Well technically, you don't have to use delegates (except when using event handlers, then it's required). You can get by without them. Really, they are just another tool in the tool box.

The first thing that comes to mind about using them is Inversion Of Control. Any time you want to control how a function behaves from outside of it, the easiest way to do it is to place a delegate as a parameter, and have it execute the delegate.



回答4:

You're not thinking like a programmer.

The question is, Why would you call a function directly when you could call a delegate?

A famous aphorism of David Wheeler goes: All problems in computer science can be solved by another level of indirection.

I'm being a bit tongue-in-cheek. Obviously, you will call functions directly most of the time, especially within a module. But delegates are useful when a function needs to be invoked in a context where the containing object is not available (or relevant), such as event callbacks.



回答5:

There are two places that you could use delegates in the Observer pattern. Since I am not sure which one you are referring to, I will try to answer both.

The first is to use delegates in the subject instead of a list of IObservers. This approach seems a lot cleaner at handling multicasting since you basically have

private delegate void UpdateHandler(string message);
private UpdateHandler Update;

public void Register(IObserver observer)
{
    Update+=observer.Update;
}

public void Unregister(IObserver observer)
{
    Update-=observer.Update;
}

public void Notify(string message)
{
    Update(message);
}

instead of

public Subject()
{
    observers = new List<IObserver>();
}

public void Register(IObserver observer)
{
    observers.Add(observer);
}

public void Unregister(IObserver observer)
{
    observers.Remove(observer);
}

public void Notify(string message)
{
    // call update method for every observer
    foreach (IObserver observer in observers)
    {
        observer.Update(message);
    }
}

Unless you need to do something special and require a reference to the entire IObserver object, I would think the delegates would be cleaner.

The second case is to use pass delegates instead of IObervers for example

public delegate void UpdateHandler(string message);
private UpdateHandler Update;

public void Register(UpdateHandler observerRoutine)
{
    Update+=observerRoutine;
}

public void Unregister(UpdateHandler observerRoutine)
{
    Update-=observerRoutine;
}

public void Notify(string message)
{
    Update(message);
}

With this, Observers don't need to implement an interface. You could even pass in a lambda expression. This changes in the level of control is pretty much the difference. Whether this is good or bad is up to you.



回答6:

A delegate is, in effect, passing around a reference to a method, not an object... An Interface is a reference to a subset of the methods implemented by an object...

If, in some component of your application, you need access to more than one method of an object, then define an interface representing that subset of the objects' methods, and assign and implement that interface on all classes you might need to pass to this component... Then pass the instances of these classes by that interface instead of by their concrete class..

If, otoh, in some method, or component, all you need is one of several methods, which can be in any number of different classes, but all have the same signature, then you need to use a delegate.



回答7:

I'm repeating an answer I gave to this question.

I've always like the Radio Station metaphor.

When a radio station wants to broadcast something, it just sends it out. It doesn't need to know if there is actually anybody out there listening. Your radio is able to register itself with the radio station (by tuning in with the dial), and all radio station broadcasts (events in our little metaphor) are received by the radio who translates them into sound.

Without this registration (or event) mechanism. The radio station would have to contact each and every radio in turn and ask if it wanted the broadcast, if your radio said yes, then send the signal to it directly.

Your code may follow a very similar paradigm, where one class performs an action, but that class may not know, or may not want to know who will care about, or act on that action taking place. So it provides a way for any object to register or unregister itself for notification that the action has taken place.



回答8:

Delegates are strong typing for function/method interfaces.

If your language takes the position that there should be strong typing, and that it has first-class functions (both of which C# does), then it would be inconsistent to not have delegates.

Consider any method that takes a delegate. If you didn't have a delegate, how would you pass something to it? And how would the the callee have any guarantees about its type?



回答9:

I've heard some "events evangelists" talk about this and they say that as more decoupled events are, the better it is.

Preferably, the event source should never know about the event listeners and the event listener should never care about who originated the event. This is not how things are today because in the event listener you normally receive the source object of the event.

With this said, delegates are the perfect tool for this job. They allow decoupling between event source and event observer because the event source doesn't need to keep a list of all observer objects. It only keeps a list of "function pointers" (delegates) of the observers. Because of this, I think this is a great advantage over Interfaces.



回答10:

Look at it the other way. What advantage would using a custom interface have over using the standard way that is supported by the language in both syntax and library?

Granted, there are cases where it a custom-tailored solution might have advantages, and in such cases you should use it. In all other cases, use the most canonical solution available. It's less work, more intuitive (because it's what users expect), has more support from tools (including the IDE) and chances are, the compiler treats them differently, resulting in more efficient code.

Don't reinvent the wheel (unless the current version is broken).



回答11:

Actually there was an interesting back-and-forth between Sun and Microsoft about delegates. While Sun made a fairly strong stance against delegates, I feel that Microsoft made an even stronger point for using delegates. Here are the posts:

http://java.sun.com/docs/white/delegates.html

http://msdn.microsoft.com/en-us/vjsharp/bb188664.aspx

I think you'll find these interesting reading...



回答12:

i think it is more related to syntatic sugar and a way to organize your code, a good use would be to handle several methods related to a common context which ones belong to a object or a static class.

it is not that you are forced to use them, you can programme sth with and without them, but maybe using them or not might affect how organized, readable and why not cool the code would be, maybe bum some lines in your code.

Every example given here is a good one where you could implement them, as someone said it, is just another feature in the language you can play with.

greetings



回答13:

Here is something that i can write down as a reason of using delegate. The following code is written in C# And please follow the comments.

public delegate string TestDelegate();
protected void Page_Load(object sender, EventArgs e)
{
    TestDelegate TD1 = new TestDelegate(DiaplayMethodD1);
    TestDelegate TD2 = new TestDelegate(DiaplayMethodD2);
    TD2 = TD1 + TD2; // Make TD2 as multi-cast delegate
    lblDisplay.Text =  TD1(); // invoke delegate
    lblAnotherDisplay.Text = TD2();


    // Note: Using a delegate allows the programmer to encapsulate a reference 
    //       to a method inside a delegate object. Its like the function pointer
    //       in C or C++.    
}
//the Signature has to be same.
public string DiaplayMethodD1()
{
    //lblDisplay.Text = "Multi-Cast Delegate on EXECUTION"; // Enable on multi-cast 
    return "This is returned from the first method of delegate explanation";
}
// The Method can be static also
public static string DiaplayMethodD2()
{
    return " Extra words from second method";
}

Best Regards, Pritom Nandy, Bangladesh



回答14:

Here is an example that might help.

There is an application that uses a large set of data. A feature is needed that allows the data to be filtered. 6 different filters can be specified.

The immediate thought is to create 6 different methods that each return the data filtered. For example

public Data FilterByAge(int age)

public Data FilterBySize(int size)

.... and so on.

This is fine but is a very limited and produces rubbish code because it's closed for expansion.

A better way is to have a single Filter method and to pass information on how the data should be filtered. This is where a delegate can be used. The delegate is a function that can be applied to the data in order to filter it.

public Data Filter(Action filter)

then the code to use this becomes

Filter(data => data.age > 30);

Filter(data => data.size = 19);

The code data => blah blah becomes a delegate. The code becomes much more flexible and remains open.