Uses of delegates in C# (or other languages)

2019-03-27 17:49发布

问题:

I have always wondered how delegates can be useful and why shall we use them? Other then being type safe and all those advantages in Visual Studio Documentation, what are real world uses of delegates.

I already found one and it's very targeted.

using System;

namespace HelloNamespace {

    class Greetings{
    public static void DisplayEnglish() {
            Console.WriteLine("Hello, world!");
    }
    public static void DisplayItalian() {
             Console.WriteLine("Ciao, mondo!");
    }
    public static void DisplaySpanish() {
             Console.WriteLine("Hola, imundo!");
         }
    }

    delegate void delGreeting();

    class HelloWorld {
        static void Main(string [] args) {

    int iChoice=int.Parse(args[0]);
    delGreeting [] arrayofGreetings={
             new delGreeting(Greetings.DisplayEnglish),
             new delGreeting(Greetings.DisplayItalian),
             new delGreeting(Greetings.DisplaySpanish)};

    arrayofGreetings[iChoice-1]();
         }
    }
}

But this doesn't show me exactly the advantages of using delegates rather than a conditional "If ... { }" that parses the argument and run the method.

Does anyone know why it's better to use delegate here rather than "if ... { }". Also do you have other examples that demonstrate the usefulness of delegates.

Thanks!

回答1:

The most common real-world everyday use of delegates that I can think of in C# would be event handling. When you have a button on a WinForm, and you want to do something when the button is clicked, then what you do is you end up registering a delegate function to be called by the button when it is clicked.

All of this happens for you automatically behind the scenes in the code generated by Visual Studio itself, so you might not see where it happens.

A real-world case that might be more useful to you would be if you wanted to make a library that people can use that will read data off an Internet feed, and notify them when the feed has been updated. By using delegates, then programmers who are using your library would be able to have their own code called whenever the feed is updated.



回答2:

Delegates are a great way of injecting functionality into a method. They greatly help with code reuse because of this.

Think about it, lets say you have a group of related methods that have almost the same functionality but vary on just a few lines of code. You could refactor all of the things these methods have in common into one single method, then you could inject the specialised functionality in via a delegate.

Take for example all of the IEnumerable extension methods used by LINQ. All of them define common functionality but need a delegate passing to them to define how the return data is projected, or how the data is filtered, sorted, etc...



回答3:

Lambda expressions
Delegates were mostly used in conjunction with events. But dynamic languages showed their much broader use. That's why delegates were underused up until C# 3.0 when we got Lambda expressions. It's very easy to do something using Lambda expressions (that generates a delegate method)

Now imagine you have a IEnumerable of strings. You can easily define a delegate (using Lambda expression or any other way) and apply it to run on every element (like trimming excess spaces for instance). And doing it without using loop statements. Of course your delegates may do even more complex tasks.



回答4:

I will try to list some examples that are beyond a simple if-else scenario:

  1. Implementing call backs. For example you are parsing an XML document and want a particular function to be called when a particular node is encountered. You can pass delegates to the functions.

  2. Implementing the strategy design pattern. Assign the delegate to the required algorithm/ strategy implementation.

  3. Anonymous delegates in the case where you want some functionality to be executed on a separate thread (and this function does not have anything to send back to the main program).

  4. Event subscription as suggested by others.



回答5:

Delegates are simply .Net's implementation of first class functions and allow the languages using them to provide Higher Order Functions.

The principle benefit of this sort of style is that common aspects can be abstracted out into a function which does just what it needs to do (for example traversing a data structure) and is provided another function (or functions) that it asks to do something as it goes along.

The canonical functional examples are map and fold which can be changed to do all sorts of things by the provision of some other operation.

If you want to sum a list of T's and have some function add which takes two T's and adds them together then (via partial application) fold add 0 becomes sum. fold multiply 1 would become the product, fold max 0 the maximum. In all these examples the programmer need not think about how to iterate over the input data, need not worry about what to do if the input is empty.

These are simple examples (though they can be surprisingly powerful when combined with others) but consider tree traversal (a more complex task) all of that can be abstracted away behind a treefold function. Writing of the tree fold function can be hard, but once done it can be re-used widely without having to worry about bugs.

This is similar in concept and design to the addition of foreach loop constructs to traditional imperative languages, the idea being that you don't have to write the loop control yourself (since it introduces the chance of off by one errors, increases verbosity that gets in the way of what you are doing to each entry instead showing how you are getting each entry. Higher order functions simply allow you to separate the traversal of a structure from what to do while traversing extensibly within the language itself.

It should be noted that delegates in c# have been largely superseded by lambdas because the compiler can simply treat it as a less verbose delegate if it wants but is also free to pass through the expression the lambda represents to the function it is passed to to allow (often complex) restructuring or re-targeting of the desire into some other domain like database queries via Linq-to-Sql.

A principle benefit of the .net delegate model over c-style function pointers is that they are actually a tuple (two pieces of data) the function to call and the optional object on which the function is to be called. This allows you to pass about functions with state which is even more powerful. Since the compiler can use this to construct classes behind your back(1), instantiate a new instance of this class and place local variables into it thus allowing closures.

(1) it doesn't have to always do this, but for now that is an implementation detail



回答6:

In your example your greating are the same, so what you actually need is array of strings.

If you like to gain use of delegates in Command pattern, imagine you have:

public static void ShakeHands()
{ ... }

public static void HowAreYou()
{ ... }

public static void FrenchKissing()
{ ... }

You can substitute a method with the same signature, but different actions. You picked way too simple example, my advice would be - go and find a book C# in Depth.



回答7:

Here's a real world example. I often use delegates when wrapping some sort of external call. For instance, we have an old app server (that I wish would just go away) which we connect to through .Net remoting. I'll call the app server in a delegate from a 'safecall ' function like this:

private delegate T AppServerDelegate<T>();

private T processAppServerRequest<T>(AppServerDelegate<T> delegate_) {
           try{
              return delegate_();
           }
           catch{
              //Do a bunch of standard error handling here which will be 
              //the same for all appserver  calls.
           }

        }

//Wrapped public call to AppServer
public int PostXYZRequest(string requestData1, string requestData2, 
   int pid, DateTime latestRequestTime){
           processAppServerRequest<int>(
              delegate {
                 return _appSvr.PostXYZRequest(
                    requestData1, 
                    requestData2, 
                    pid, 
                    latestRequestTime);  
              });

Obviously the error handling is done a bit better than that but you get the rough idea.



回答8:

Delegates are used to "call" code in other classes (that might not necessarily be in the same, class, or .cs or even the same assembly).

In your example, delegates can simply be replaced by if statements like you pointed out.

However, delegates are pointers to functions that "live" somewhere in the code where for organizational reasons for instance you don't have access to (easily).



回答9:

Delegates and related syntactic sugar have significantly changed the C# world (2.0+) Delegates are type-safe function pointers - so you use delegates anywhere you want to invoke/execute a code block at a future point of time.

Broad sections I can think of

Callbacks/Event handlers: do this when EventX happens. Or do this when you are ready with the results from my async method call.

myButton.Click += delegate { Console.WriteLine("Robbery in progress. Call the cops!"); }

LINQ: selection, projection etc. of elements where you want to do something with each element before passing it down the pipeline. e.g. Select all numbers that are even, then return the square of each of those

var list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
                 .Where(delegate(int x) { return ((x % 2) == 0); })
                 .Select(delegate(int x) { return x * x; });    
// results in 4, 16, 36, 64, 100


回答10:

Another use that I find a great boon is if I wish to perform the same operation, pass the same data or trigger the same action in multiple instances of the same object type.



回答11:

In .NET, delegates are also needed when updating the UI from a background thread. As you can not update controls from thread different from the one that created the controls, you need to invoke the update code withing the creating thread's context (mostly using this.Invoke).