By default use methods, it has the smallest indirect possible. If it’s a simple static or instance method, there’s only the minimum necessary indirect that is to send to the part of the code where it’s written or even in some cases with optimizations it can even delete it and copy the code and be faster, is a very simple mechanism.
When you need the method to be customized into a class that derives from yours then you need to leave the method virtual
. In this case it practically prevents optimization and there is an extra level of indirect to find out which is the concrete type of the object before deciding which method to call, whether it is from the base class or derivative. That’s the thing about polymorphism.
But it may be that you need more customization, you may want each instance of the object to have a custom action in that method, it is not enough to just let the derived class customize the method implementation. In this case you need to have an infrastructure within the instance that controls this, and that’s where the anonymous method comes in.
This form create a variable that is of a type delegate
, so she’s an extra indirect like the virtual
is, and today can never be optimized, even in the future few cases would be possible and with high cost for the compiler.
Done this you have the implementation of the field Escrever
or Soma
as an object that will have as its basic value the implementation of a method, which is nothing more than a body of a normal method, but it will not have a statically bound name in it.
This way you can create an object and place the implementation you want and change the execution. You can determine a different way of doing such writing or summing that is to be done. You can even switch in the middle of the execution. In the declared form, the value is free to be exchanged, as well as any variable of the type int
or string
, then you can say that "now" the method to be executed has another implementation, for example:
objeto.Escrever => Write($"Tenho um texto para te dizer: {texto}");
This will not execute anything, it will only change the value of the field Escrever
. To perform this you have to call:
objeto.Escrever()
No need to use the Invoke()
.
In general you don’t want the implementation to be changed on the object in the middle of its execution, so you can do so:
public readonly Action<string> Escrever;
And then in the builder do something like this:
this.Escrever = (texto) => WriteLine(texto);
The this
probably not necessary, it was more to illustrate.
If you just do
public readonly Action<string> Escrever = (texto) => WriteLine(texto);
does not make sense, in this case it is better to use a normal method, after all you can not customize at any time that would be the goal of this.
And if you do
public static readonly Action<string> Escrever = (texto) => WriteLine(texto);
there is only a much more complicated and inefficient way of doing
public void Escrever(texto) => WriteLine(texto);
There are some questions that explain better the internal mechanism of anonymous function, especially me c. And there are also others who talk about the loading of cloistered variables.
Both can use the type syntax lambda (=>
) and make the code less verbose.
public Func<int, int, int> Soma = (n1, n2) => n1 + n2;
public int Soma(int n1, int n2) => n1 + n2;
I put in the Github for future reference.
See more in:
I think this isn’t about method being different, you’re just defining that return of
Escrever
will be classAction
usingstring
as Constraint.– Wallace Maxters
The second case, usually
Func
is used to define local functions (or anonymous, I’m not sure what it’s called in C#). It’s very reminiscent of PHP closures and javascript.– Wallace Maxters