How to declare a function inside another function in C #?

7

In Delphi it is possible to declare function within the block of a given function, see this example done in Delphi:

procedure TForm1.btnRunClick(Sender: TObject);
begin
  mostrarNome('Carvalho');
end;

function TForm1.mostrarNome(nome: String): String;
  function transformaMaiuscula(str: String): String;
  begin
    Result := UpperCase(str);    
  end;
begin
  ShowMessage(transformaMaiuscula(nome));
end;

The output will be:

  

CARVALHO // In capital letters

So, I'd like to know if it's possible to do the same in C #, declaring a function inside another function. See this code in C #:

class Program
{
    static void Main(string[] args)
    {
        mostraNome("Carvalho");

        Console.ReadKey();
    }

    static void mostraNome(string nome) 
    {
        static string transformaMaiuscula(string str)
        {
            return str.ToUpper();
        }

        Console.WriteLine(transformaMaiuscula());
    }
}

The code in C # above does not work, the compiler says that the syntax is invalid, but it's just an illustration.

Is there a way to do this in C #?

    
asked by anonymous 24.05.2016 / 03:20

2 answers

7

Gambiarra

Until C # 6 the only way was to use lambda than anything more is a pointer to function (eventually it can store captured variables as well), so it is possible to write the body of a function and store in a variable or pass as argument, or else to return in the function that was declared.

Func<string string> transformaMaiuscula = (string str) => str.ToUpper();
transformaMaiuscula("Teste"); //obviamente pode fazer o que quiser

This feature is a syntactic sugar above delegates .

It exists since C # 3. In C # 2 there was the syntax of delegate which is similar to lambda syntax but less convenient. In C # 1 there was delegate , but the syntax was so inconvenient that you had to declare the delegate and then declare and define a separate method, that is, could not declare within another method.

Func<string string> transformaMaiuscula = delegate(string str) {
    return str.ToUpper();
};
Console.WriteLine(transformaMaiuscula(nome));

This Func<string string> is an already declared delegate by .Net, for your convenience. In other circumstances you could also Action and a Predicate . Only Predicate existed in C # 2, which was very limiting, which meant in practice to declare the delegate out of the method.

I will not even use the C # example because it does not even look like what is being requested, but the delegate's declaration would be delegate string transformaMaiuscula(string str) , then declare the method with the same signature. The declaration goes inside a type, but not within a method.

Note that using a delegate with lambda syntax is quite different from using a normal . You can even simulate this idea, but they have different characteristics. And it is a tremendous gambiarra to do that. It even has memory consumption, processing overhead and possible loss of reliability in more complex cases if the programmer does not take certain care.

If you need a delegate, then fine, pay the price to use it. That's not the question.

Syntax lambda out of method

C # 6 even allowed the lambdas syntax to be used in any method, so when the method is too simple, it is easier to declare your body. It passed the lamba syntax, but not its semantics. It could only be used in normal type methods.

string transformaMaiuscula(string str) => str.ToUpper();

Not that this helps the question, I put it as a curiosity because people are slow to get used to new features.

Correct solution

There you can think: what will you do if you have nothing else? Well, I would not use a lambda when only a local (nested) function is desired, as the question shows. My solution, and this is the official recommendation, is simply to undo the function. Just create a separate, probably private, static method and call it where you need it.

It only has one drawback, other methods of the class may call it. But it is manageable and does not generate any other cost.

private static string transformaMaiuscula(string str) => str.ToUpper();

Then, within your method, simply call the transformaMaiuscula method as any other method.

C # 7

In C # 7 it is already possible to use the local function syntax, so you do not pay any price, there is no risk. Not even to allow the call of this function by other members of the class.

It seems like the syntax would almost be used by AP:

static void mostraNome(string nome) {
    string transformaMaiuscula(string str) {
        return str.ToUpper();
    }
    Console.WriteLine(transformaMaiuscula(nome));
}

I have not seen details (update when I see) as a static method, but I see no point in having to put the internal method as static, I do not think it is even allowed, it will have the lifetime of its parent method. p>

Note that you can declare the local method after using it. It is not possible to do this with lambda .

When you leave the final version of C # 7 it would be interesting to ask a question about all the details of this feature.

    
24.05.2016 / 14:19
6

Directly, no. But you can declare a Action or delegate , or even Func<> , which is almost the same thing.

using System;

public class Program
{
    delegate void Teste2();

    public static void Main()
    {
        Action Teste = () =>
        {
            Console.WriteLine("Teste!");
        };

        Teste2 teste2 = delegate() {
            Console.WriteLine("Teste 2!");
        };

        Func<string, string> teste3 = delegate(string argumento) {
            return argumento + " " + argumento;
        };

        Teste();
        teste2();
        Console.WriteLine(teste3("Buemba!"));
        Console.WriteLine("Hello World");
    }
}

I made a Fiddle .

Result:

Teste!
Teste 2!
Buemba! Buemba!
Hello World

The difference between them is that delegate needs to be strongly typed. Action is a bit more dynamic, but returns no value at all. To return values, use Func<TArgumentos, TRetorno> , where TRetorno is what will be returned and TArgumentos are the types of arguments.

    
24.05.2016 / 03:40