When and where to use a delegate in C#?

Asked

Viewed 5,656 times

14

I’m new to C# and I still don’t fully understand the concept of using a delegate:

public delegate void HTTPRequestsHandler(string url);

I would like to know when to use them and in which cases a delegate is useful.

2 answers

13


Your question is very similar to this, but the context is a little different.

Delegates can be roughly defined to types that define functions. In its example:

public delegate void HTTPRequestsHandler(string url);

You’re defining the type HTTPRequestsHandler, which is a type of function that returns nothing, and whose argument is a string.

The main use of delegates is to define functions at runtime. In this example, the idea should be to define a function that handles HTTP requests already with the application running.

Suppose you write a server that receives HTTP requests, but wants to give others the freedom to write exactly how they want the request to be processed. Your server will expect a runtime function, and your code will only focus on calling this function at the appropriate time.

Examples

Without delegate

Suppose a class like this:

public class MeuServidor
{
    public void MinhaFuncaoQueTrataHttpRequests(string url) 
    {
        /* Note que aqui preciso declarar minha função. 
           Não tenho a opção de declarar ela em outro momento. */
    }
}

With delegate

Suppose the statement both of the delegate how much of my class so:

public delegate void HTTPRequestsHandler(string url);

public class MeuServidor
{
    public HTTPRequestsHandler minhaFuncaoDelegate { get; set; }
}

Note that it appears as property, and that I can use the set to define it at another point in the code. Thus:

HTTPRequestsHandler delegateEmOutroLugar = delegate(string url) {
    /* Faço alguma coisa aqui, como uma função. */
};

var meuServidor = new MeuServidor();
// Posso definir agora minha função de delegate, assim:
meuServidor.minhaFuncaoDelegate = delegateEmOutroLugar;
// E executar assim:
meuServidor.minhaFuncaoDelegate("http://umsitequalquer");
  • I could give an example with and without delegate?

  • @Rowaraujo Updated the answer.

11

Roughly speaking, it’s a way to store a code in a variable. In other words, in a somewhat simplified way, the value of the variable is a code that can be invoked at some point.

When to use

The general idea indicates the use whenever you want to allow an action to be configured a posteriori.

An example of using the general idea is LINQ. He knows how to perform certain actions but doesn’t know the specific details of how to do this, so he expects you to pass code to him:

objeto.Where(x => x == 0);

Within the Where() is done a number of things. At a certain point he needs to decide whether to take a data or not. This decision Where() does not know what it is, so it gets a code that defines how to make the comparison. This code is what is being passed there as argument from Where(). Inside this will be executed as if it were a method, and the result is that it will be used. Note that this code will not be executed there. It will run inside at the time it is useful, as many times as necessary. And on each call it will be passed by the code inside the Where() an argument, which will be received by this code as the parameter x.

This is called callback Function, since we have defined a function that will be used as "parameter" of what to execute (call back).

This is a form of delegation, but not in the way presented in the question.

In events it is another great use, after all the event always needs to call a certain method that it does not know exactly what it does. He only knows what the contract of this method is like. It is something external to his knowledge. Another piece of code will tell what the actual implementation is.

Delegate in the form presented in the pegunta practically should not be used. This form was needed at the beginning of C# and is still needed in very specific cases, in general, to create a better abstraction.

Its operation

When we create a delegate we are telling the code that we will have something there that needs to be executed, but we still do not know exactly what, we only know how the call should be made.

The form presented is only the statement delegate. As its name says is a way to delegate an action to a code that will be established. The statement consists only of the signature of the method expected. This is important for the compiler to know how to treat that specific delegate, and generates a new type in the application.

So every time a variable is created using this type it will know how to properly invoke the method according to the given signature. The variable will store a reference to a particular method created at some point in the application development. When we assign a code to the variable that will be delegated we are defining its value. That is, we are pointing out a specific behavior that will be worth until another code changes the note.

The moment we make a method call through this delegated variable, we are running the code that is pointed out by her.

When we create this form of delegation we are telling the code that we know that a certain method needs to exist there, and we know what its signature is. We just don’t know yet what its body is, what it actually does in concrete implementation. Some other part of the code will tell us what it should do. And it is possible to change what must be executed at any time at runtime.

Terminology

If you know other languages this is the same as a Function Pointer. The delegate is one of the ways to have a pointer to a function. There are other synonyms or related terms.

More modern form

Today, in C#, we use more lambda, which is an anonymous function with a simpler syntax and which, in general, waives the delegate’s statement.

That doesn’t mean he doesn’t exist, just that you don’t have to write it. The compiler infers the signature of that method and creates the delegate for you. In some cases where inference is not possible, you can use a Func or Action to replace the delegate’s declaration.

Ways to define the code

Of course, the method or loose code must exist and be compiled beforehand (it is even possible to do this compilation at runtime, but this is less common and it has only recently become easier to do this). The concrete method that should be used can be defined in the traditional way or by the syntax of lambda or of delegate (note that the keyword delegate is used to declare a delegate and also to define one, but both are uncommon today, since the use of lambda is more convenient*).

You can use any existing method in the application, including existing methods on . NET as a concrete implementation of a delegate. Sure, as long as the signature matches the one stated on the delegate. There are methods that have a hidden member who is the one this, then it may seem that one method has the same signature and is actually another.

So your example could be defined like this:

public static void Metodo(string url) => WriteLine(url); // só um exemplo

And that would define the delegate:

HTTPRequestsHandler handler = Metodo; //é o método acima

Or it can simplify a little and make the definition of the method and the delegate at the same time:

HTTPRequestsHandler handler = delegate(string url) {
    WriteLine(url); // só um exemplo
};

Or how lambda (HTTPRequestsHandler nor need to exist):

var handler = (string url) => WriteLine(url); // só um exemplo

Comparing to interfaces

Knows well the use of interfaces or abstract classes? An interface closely resembles a delegate, but the interface embodies the method in a fixed form and defined at compile time. The delegate can be set at runtime (although the code itself to be executed will also be set at compile time).

interface IManipulador {
    public void HTTPRequestsHandler(string url);
}

class Exemplo : IManipulador {
     public void HTTPRequestsHandler(string url) => WriteLine(url); // só um exemplo
}

Did the same thing. Any class that implements the interface Manipulador can have a method that is guaranteed that meets the needs (the signature) imposed on the delegate. Only you don’t have the flexibility to change at runtime.

public delegate void HTTPRequestsHandler(string url);

class Exemplo {
     public HTTPRequestsHandler handler = (string url) => WriteLine(url); // só um exemplo
}

Then you can do:

var x = new Exemplo();
x.handler("http://dominio.br/pagina.html"); //escreve isto pulando uma linha
x.handler = (string url) => Write(url);
x.handler("http://dominio.br/pagina.html"); //escreve isto sem pular a linha

Okay, you’ve changed what you should actually do, now print without skipping line. The example is silly but shows flexibility. The consumer of this class can tell how the manipulator should be. Of course if not careful can abuse it.

This is a way to avoid inheritance and polymorphism and various situations (even if this is a form of polymorphism). Doesn’t mean I should at all, of course, everything has the right time to use.

This class could be written in the most modern way avoiding the delegate’s statement:

class Exemplo {
     public Action<string> handler = (string url) => WriteLine(url); // só um exemplo
}

In this particular case, since WriteLine() has a compatible signature, can do even better:

class Exemplo {
     public Action<string> handler = WriteLine; // só um exemplo
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

More information

Could you speak of delegates multicast and its use mainly with events. But it’s better to understand one part at a time.

Very interesting article on the subject.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.