C#: Como criar e utilizar funções
CSharp
Fala, dev! Se você está começando no universo da programação e já ouviu falar de métodos, prepare-se, pois eles vão te ajudar a escrever códigos mais organizados e eficientes. Hoje, vamos falar sobre como criar e utilizar métodos no C#. Eu prometo que, ao final deste artigo, você vai dominar esse conceito como um verdadeiro ninja do código. E aí, bora para mais uma missão?
📽️
Antes de mergulharmos nas funções em C#, que tal dar uma olhada neste vídeo? Descubra 5 motivos essenciais para dominar métodos em C# que vão elevar suas habilidades de programação!
Video preview

O que são métodos e por que usá-los?

Em C#, métodos (também conhecidos como funções em outros contextos) são blocos de código que executam uma tarefa específica. Na verdade, em C#, todas as funções estão dentro de classes e, portanto, são chamadas de métodos.
Os métodos permitem que você escreva um código uma vez e o reutilize sempre que precisar, tornando seu programa mais modular, legível e fácil de manter. Pense nos métodos como pequenas ferramentas especializadas que, juntas, constroem algo maior.
Quer um exemplo? Se você precisa calcular a soma de números em várias partes do seu programa, em vez de repetir o código de soma em cada lugar, você cria um método Somar e o chama sempre que precisar somar números.

Sintaxe Básica de um Método em C#

Criar um método em C# é simples e direto. Vamos ver como ele é formado:
public static int Somar(int a, int b) { return a + b; }

Componentes Principais de um Método em C#:

  • Modificador de acesso: especifica quem pode acessar o método.
    • public: o método pode ser acessado de qualquer lugar.
    • private: o método só pode ser acessado dentro da classe em que foi declarado.
    • protected: o método pode ser acessado dentro da classe e por classes derivadas.
    • internal: o método pode ser acessado dentro do mesmo assembly.
    • protected internal: combina as funcionalidades de protected e internal.
    • private protected: disponível a partir do C# 7.2, restringe o acesso a dentro da classe ou tipos derivados no mesmo assembly.
Escolher o modificador de acesso adequado é importante para encapsular e proteger os dados e funcionalidades da sua classe.
  • static: indica que o método pertence à classe e não a uma instância específica. Pode ser chamado diretamente pela classe.
  • Tipo de Retorno: o tipo de dado que o método irá retornar. Se o método não retornar nada, usamos void.
  • Nome do Método: deve ser descritivo e seguir as convenções de nomenclatura da linguagem.
  • Parâmetros: dados de entrada que o método recebe para realizar suas operações.
  • Corpo do Método: bloco de código que contém as instruções a serem executadas.

Exemplo Completo:

Vamos ver como esse método é utilizado no código:
class Program { static void Main(string[] args) { int resultado = Somar(5, 3); Console.WriteLine("Resultado: " + resultado); } public static int Somar(int a, int b) { return a + b; } }
Quando você executa o código acima, o método Somar será chamado, somará os dois números e retornará o resultado.

Passagem de parâmetros

No C#, podemos passar parâmetros de quatro maneiras: por valor, por referência, como saída e somente leitura. Vamos entender como isso funciona.

1. Passagem por valor

Por padrão, os parâmetros em C# são passados por valor, ou seja, o método recebe uma cópia do valor original. Isso significa que alterações feitas dentro do método não afetam o valor original.
class Program { static void DobrarValor(int x) { x = x * 2; } static void Main(string[] args) { int numero = 5; DobrarValor(numero); Console.WriteLine("Número após DobrarValor: " + numero); // Saída: 5 } }
Como o valor é passado por cópia, o valor original não é alterado.

2. Passagem por referência

Se você quiser que o método altere diretamente o valor original, pode usar a palavra-chave ref para passar o parâmetro por referência.
class Program { static void DobrarReferencia(ref int x) { x = x * 2; } static void Main(string[] args) { int numero = 5; DobrarReferencia(ref numero); Console.WriteLine("Número após DobrarReferencia: " + numero); // Saída: 10 } }
Aqui, o valor de numero é alterado diretamente dentro do método porque ele foi passado por referência.

3. Parâmetros de saída com out

A palavra-chave out permite que um método retorne múltiplos valores.
class Program { static void ObterValores(out int x, out int y) { x = 10; y = 20; } static void Main(string[] args) { int a, b; ObterValores(out a, out b); Console.WriteLine($"Valores obtidos: a = {a}, b = {b}"); // Saída: Valores obtidos: a = 10, b = 20 } }
Com out, os parâmetros devem ser inicializados dentro do método antes de serem usados.
  • O parâmetro passado com ref deve ser inicializado antes de ser passado para o método.
  • O parâmetro passado com out não precisa ser inicializado antes da chamada do método, mas deve ser atribuído dentro do método antes que ele termine.

Parâmetros somente leitura com in

Introduzida no C# 7.2, a palavra-chave in permite passar parâmetros por referência de forma somente leitura, melhorando o desempenho em certos cenários.
class Program { static void ExibirValor(in int x) { // x = x * 2; // Isso causaria um erro de compilação, pois x é somente leitura. Console.WriteLine($"Valor de x: {x}"); } static void Main(string[] args) { int numero = 5; ExibirValor(numero); } }
O uso de in é útil quando você está passando estruturas grandes por valor e deseja evitar a cópia, mas sem permitir modificações no valor original.

Retorno de valores: métodos com e sem retorno

Nem todos os métodos precisam retornar valores. Quando um método não retorna nada, usamos void. Mas, se você quiser que o método devolva um valor, basta declarar o tipo de retorno e usar a palavra-chave return.

Exemplo de um método com retorno:

class Calculadora { public int Multiplicar(int a, int b) { return a * b; } } class Program { static void Main(string[] args) { Calculadora calc = new Calculadora(); int produto = calc.Multiplicar(4, 5); Console.WriteLine("Produto: " + produto); // Saída: Produto: 20 } }

Exemplo de um método sem retorno (void):

class Mensagem { public void ExibirMensagem() { Console.WriteLine("Olá, dev!"); } } class Program { static void Main(string[] args) { Mensagem msg = new Mensagem(); msg.ExibirMensagem(); // Saída: Olá, dev! } }
Use métodos com retorno quando precisar que o método devolva um resultado. Caso contrário, void é a melhor opção.

Funções anônimas e expressões lambda

Métodos anônimos são métodos sem nome que você pode atribuir a variáveis ou passar como argumentos para outros métodos. Em C#, podemos criar funções anônimas usando métodos anônimos (com a palavra-chave delegate) ou expressões lambda, que são uma maneira mais concisa e moderna.

Exemplo de uma função anônima usando lambda:

using System; class Program { static void Main(string[] args) { Func<int, int, int> somar = (a, b) => a + b; Console.WriteLine(somar(10, 20)); // Saída: 30 } }
Nesse exemplo, criamos uma função anônima que soma dois números e a atribuímos à variável somar. Essa sintaxe é muito comum quando estamos trabalhando com coleções e LINQ. LINQ? Não se preocupe, vou explicar logo abaixo.

Introdução ao LINQ

LINQ (Language Integrated Query) é um conjunto de recursos que adiciona capacidades de consulta às linguagens .NET. Expressões lambda são frequentemente usadas com LINQ para escrever consultas de forma concisa e expressiva.
using System; using System.Linq; using System.Collections.Generic; class Program { static void Main(string[] args) { List<int> numeros = new List<int> { 1, 2, 3, 4, 5 }; var numerosPares = numeros.Where(n => n % 2 == 0); Console.WriteLine("Números pares:"); foreach (var num in numerosPares) { Console.WriteLine(num); } } }
No exemplo acima, usamos uma expressão lambda n => n % 2 == 0 dentro do método Where que filtra os números pares da lista.

Sobrecarga de métodos

Sobrecarga de métodos é um recurso poderoso do C# que permite criar várias versões de um mesmo método, cada uma com diferentes parâmetros.

Exemplo de sobrecarga:

class Calculadora { public int Somar(int a, int b) { return a + b; } public double Somar(double a, double b) { return a + b; } public int Somar(int a, int b, int c) { return a + b + c; } } class Program { static void Main(string[] args) { Calculadora calc = new Calculadora(); int resultadoInt = calc.Somar(5, 3); Console.WriteLine("Resultado (int): " + resultadoInt); // Saída: 8 double resultadoDouble = calc.Somar(5.5, 3.2); Console.WriteLine("Resultado (double): " + resultadoDouble); // Saída: 8.7 int resultadoTres = calc.Somar(1, 2, 3); Console.WriteLine("Resultado (três parâmetros): " + resultadoTres); // Saída: 6 } }
Aqui, temos três métodos Somar, cada um com diferentes tipos e números de parâmetros. Isso nos dá mais flexibilidade na hora de reutilizar métodos com diferentes entradas.

Classes, instâncias e o método Main no C#

No C#, todo código executável precisa estar dentro de uma classe. O método Main é o ponto de entrada do programa e é sempre executado primeiro. Até agora, usamos métodos estáticos, mas o que acontece quando queremos trabalhar com métodos não estáticos e propriedades de instância?

Métodos de instância vs. métodos estáticos

  • Métodos Estáticos: pertencem à classe em si e podem ser chamados sem criar um objeto. Usamos o modificador static na declaração.
  • Métodos de Instância: pertencem a um objeto específico da classe. Para usá-los, precisamos criar uma instância (objeto) da classe.

Exemplo prático:

Vamos criar uma classe Pessoa que possui um método não estático para apresentar informações pessoais.
class Pessoa { private string nome; private int idade; // Construtor da classe public Pessoa(string nome, int idade) { this.nome = nome; this.idade = idade; } // Método de instância public void Apresentar() { Console.WriteLine($"Olá, meu nome é {nome} e tenho {idade} anos."); } } class Program { static void Main(string[] args) { // Criando uma instância da classe Pessoa Pessoa pessoa1 = new Pessoa("Maria", 30); pessoa1.Apresentar(); // Podemos criar várias instâncias com dados diferentes Pessoa pessoa2 = new Pessoa("João", 25); pessoa2.Apresentar(); } }
Neste exemplo, o método Apresentar é um método de instância, pois ele depende dos dados específicos de cada objeto Pessoa. Para chamá-lo, precisamos criar uma instância da classe usando new Pessoa(...).

Por que isso é importante?

Entender a diferença entre métodos estáticos e de instância é fundamental para estruturar seu código de forma eficiente. Métodos estáticos são úteis para operações que não dependem de dados de instância, como funções utilitárias. Já métodos de instância são ideais quando a operação depende dos dados armazenados no objeto.

Métodos recursivos

Recursão é quando um método chama a si mesmo. Esse conceito é útil em problemas que podem ser divididos em subproblemas menores, como o cálculo de fatorial.

Exemplo de método recursivo:

class Program { static int Fatorial(int n) { if (n < 0) { throw new ArgumentException("Não é possível calcular o fatorial de um número negativo."); } if (n == 0 || n == 1) { return 1; } return n * Fatorial(n - 1); } static void Main(string[] args) { int numero = 5; try { int resultado = Fatorial(numero); Console.WriteLine($"Fatorial de {numero} é {resultado}"); // Saída: Fatorial de 5 é 120 } catch (ArgumentException ex) { Console.WriteLine(ex.Message); } } }

Explicação do código:

  1. Condição de erro para números negativos: o método verifica se o número n é negativo e lança uma exceção ArgumentException se for. Isso impede o cálculo de fatoriais negativos, que não são definidos matematicamente.
  1. Condição de parada: se n for 0 ou 1, o método retorna 1, pois o fatorial de 0 e 1 é 1. Essa é a condição de parada da recursão.
  1. Chamada recursiva: para valores maiores que 1, o método se chama novamente com o valor n-1, acumulando o produto de n * (n-1) * (n-2) * ... * 1.
  1. Tratamento de exceção: no método Main, o try-catch captura a exceção de números negativos e exibe a mensagem apropriada ao usuário.
Percebeu? O método Fatorial chama a si mesmo até atingir a condição base. Adicionamos uma verificação para números negativos, exibindo uma mensagem de erro quando aplicável.

Boas práticas ao criar métodos

  1. Nomes claros e descritivos: escolha nomes que indiquem claramente o que o método faz.
  1. Métodos com responsabilidade única: cada método deve fazer uma única coisa. Isso facilita a manutenção e o entendimento do código.
  1. Documentação: use comentários para explicar o propósito do método, especialmente em métodos mais complexos.
  1. Evite muitos parâmetros: se um método precisar de muitos parâmetros, talvez seja hora de repensar o design.
  1. Consistência: mantenha um estilo consistente de codificação em todo o projeto.

Conclusão

Métodos são uma parte fundamental do C#. Eles tornam o código mais organizado, reutilizável e eficiente. Neste artigo, exploramos desde a criação de métodos simples até conceitos mais avançados, como métodos anônimos, recursão e sobrecarga de métodos. Agora é hora de praticar e aplicar esses conceitos nos seus projetos!
Se você quer se aprofundar ainda mais e dominar o C#, não deixe de conferir a formação C# da Rocketseat. Lá você vai aprender com projetos práticos e se preparar para criar aplicações robustas e escaláveis!

Além deste artigo, não deixe de conferir outros conteúdos sobre C# no nosso blog:
E claro, continue praticando! A prática é a chave para dominar qualquer linguagem.

Aprenda programação do zero e DE GRAÇA

No Discover você vai descomplicar a programação, aprender a criar seu primeiro site com a mão na massa e iniciar sua transição de carreira.

COMECE A ESTUDAR AGORA