Um método é um bloco de código com nome que recebe entradas (parâmetros), faz seu trabalho e pode devolver um resultado (o valor de retorno). Em C#, todo método fica dentro de um tipo; não existem funções soltas.
Saída:
Headphones 48.00
Cable 11.40
Anatomia de um método
public static decimal PriceWithTax(decimal net, decimal taxRate)
{
return net * (1 + taxRate);
}
- Modificador de acesso (
public,private, ...): quem pode chamá-lo. Se omitido, o método éprivatedo seu tipo. static: o método pertence ao tipo, não a um objeto. Mais sobre isso abaixo.- Tipo de retorno: o tipo do valor que ele retorna, ou
voidquando não retorna nada. - Nome: PascalCase por convenção, normalmente um verbo (
Calculate,SendEmail,TryParse). - Lista de parâmetros: zero ou mais pares
type name. Cada parâmetro é uma variável local inicializada com o argumento de quem chama. - Corpo: as instruções entre as chaves.
O nome mais os tipos dos parâmetros (e quaisquer modificadores ref, out ou in) formam a assinatura do método. O tipo de retorno não faz parte dela, o que importa para a sobrecarga.
Valores de retorno e void
return encerra o método imediatamente e devolve um valor. Um método com tipo de retorno precisa retornar um valor desse tipo em todos os caminhos possíveis:
static string Grade(int score)
{
if (score >= 50)
return "pass";
} // error CS0161: 'Program.Grade(int)': not all code paths return a value
O compilador verifica cada ramo. Adicione o return "fail"; que falta, ou um throw se chegar a esse ponto for um bug.
Um método void não retorna nada. Ele ainda pode usar um return; sozinho para sair antes:
Saída:
ana@mail.com: newsletter sent
ben@mail.com: not subscribed, skipped
False
True
Métodos com corpo de expressão
Quando o corpo de um método é uma única expressão, => substitui as chaves e o return:
static decimal Discount(decimal price) => price * 0.1m;
static bool IsAdult(int age) => age >= 18;
static void Log(string message) => Console.WriteLine($"[log] {message}");
É o mesmo método, escrito de forma mais curta. Funciona também para métodos void, desde que o corpo seja uma expressão (uma chamada, uma atribuição).
Parâmetros são cópias
Por padrão, os argumentos são passados por valor: o parâmetro recebe uma cópia do argumento. Atribuir ao parâmetro dentro do método não afeta a variável de quem chamou:
Saída:
inside: 42
after: 21
scores: 70, 85, 100
A List mudou porque, para um tipo de referência, o valor copiado é a referência: o método e quem chamou apontam para o mesmo objeto lista. Reatribuir scores = new List<int>() dentro do método não afetaria quem chamou. Para permitir que um método atribua à variável de quem chamou, use ref ou out; para dar valores padrão aos parâmetros e chamá-los pelo nome, use parâmetros opcionais e argumentos nomeados.
Retornando vários valores com uma tupla
Desde o C# 7.0, um método pode retornar uma tupla com elementos nomeados, e quem chama pode desconstruí-la em variáveis separadas:
Saída:
min 15, max 27, avg 21.0
range 12
_ descarta o elemento de que você não precisa. Para resultados usados em muitos lugares, uma classe pequena ou um record com propriedades nomeadas documenta a forma melhor que uma tupla.
Sobrecarga
Vários métodos podem ter o mesmo nome se as listas de parâmetros diferirem em número, tipos ou ordem dos tipos. O compilador escolhe a melhor correspondência para cada chamada:
Saída:
12.57
13.50
25
Area(5) escolhe a versão int porque é uma correspondência exata; Area(2.0) escolhe a versão double. Métodos não podem diferir só pelo tipo de retorno: dois métodos Area(int) retornando int e double são o erro CS0111, Type 'Program' already defines a member called 'Area' with the same parameter types, porque uma chamada como Area(5) não teria como distingui-los.
Uma chamada que nenhuma sobrecarga aceita também falha em tempo de compilação: Area(1, 2, 3) é CS1501, No overload for method 'Area' takes 3 arguments, e Area("big") é CS1503, Argument 1: cannot convert from 'string' to 'double'.
params: um número variável de argumentos
Um parâmetro array params aceita qualquer quantidade de argumentos, inclusive nenhum. O compilador monta o array para você:
Saída:
empty cart: 0 item(s), 0
one item: 1 item(s), 9.99
three items: 3 item(s), 19.75
from array: 2 item(s), 50
Regras: params precisa ser o último parâmetro (senão é CS0231), um método tem no máximo um, e passar um array existente entrega esse array como está. Console.WriteLine("{0} and {1}", a, b) e string.Format são métodos params object[]. O C# 13 estendeu o params para outros tipos de coleção, como List<T> e ReadOnlySpan<T>; antes disso, só arrays eram permitidos.
Métodos static e de instância
Um método static pertence ao tipo e é chamado pelo nome do tipo: Math.Max(3, 7), Program.Total(...). Um método de instância pertence a um objeto e pode usar os campos desse objeto:
Saída:
12
Chamar um método de instância a partir de um static sem um objeto é o erro de iniciante mais comum em C#:
class Program
{
void Greet() => Console.WriteLine("hi");
static void Main()
{
Greet();
// error CS0120: An object reference is required for the non-static field, method, or property 'Program.Greet()'
}
}
Marque Greet como static, ou crie um objeto e faça a chamada nele: new Program().Greet();. A página de static cobre membros static e classes static com mais profundidade.
O método Main
Main é onde um programa começa. Ele precisa ser static, e estas assinaturas são válidas:
static void Main() { }
static void Main(string[] args) { } // command-line arguments
static int Main(string[] args) { return 0; } // exit code for the shell
static async Task Main() { } // C# 7.1 and later
A forma async Task Main permite que o ponto de entrada use await diretamente (veja async e await). Desde o C# 9, um arquivo pode conter instruções de nível superior no lugar: código sem nenhuma classe nem Main, como em um projeto novo criado com dotnet new console. O compilador gera a classe e o método Main em volta dele, então é a mesma coisa escrita de forma mais curta; args continua disponível.
Recursão
Um método pode chamar a si mesmo. Cada chamada tem seus próprios parâmetros e variáveis locais, e um caso base precisa encerrar a cadeia:
Saída:
120
2432902008176640000
35
Sem caso base, ou com uma entrada profunda demais, cada chamada adiciona um quadro à pilha até o programa morrer com StackOverflowException. Essa exceção não pode ser capturada, então para entradas de profundidade desconhecida reescreva a recursão como um laço.
Funções locais
O C# 7.0 introduziu as funções locais: métodos declarados dentro de outro método, visíveis só ali. Elas podem usar as variáveis do método que as contém:
// C# 7.0 and later
static int CountValid(string[] codes)
{
int count = 0;
foreach (string code in codes)
{
if (IsValid(code)) count++;
}
return count;
bool IsValid(string c) => c.Length == 6 && char.IsLetter(c[0]);
}
Elas mantêm um auxiliar ao lado do único lugar que o chama, sem expô-lo para o resto da classe. Desde o C# 8 elas podem ser marcadas como static para proibir a captura de variáveis externas. Onde uma função local não está disponível, um método private static na mesma classe faz o mesmo trabalho, como nos outros exemplos desta página.
Perguntas frequentes
Qual a diferença entre método e função em C#?
Em C#, toda função é declarada dentro de uma classe, struct ou record, e é chamada de método. Não existem funções soltas. Até as instruções de nível superior (C# 9) e as funções locais (C# 7) são compiladas como métodos de um tipo gerado ou de um tipo que as contém. "Função" é usado informalmente, e para lambdas e delegates.
O que o params faz em C#?
params permite que um método receba um número variável de argumentos de um tipo: static int Sum(params int[] numbers) pode ser chamado como Sum(), Sum(4), Sum(4, 5, 6) ou Sum(existingArray). O compilador junta os argumentos em um array. O parâmetro params precisa ser o último, e um método só pode ter um.
O que é o método Main em C#?
Main é o ponto de entrada do programa: o método que o runtime chama primeiro. Ele precisa ser static, pode retornar void ou int (o código de saída) e pode receber string[] args com os argumentos da linha de comando. Desde o C# 7.1 ele também pode ser async Task Main, e desde o C# 9 as instruções de nível superior deixam o compilador gerá-lo para você.
Como retornar vários valores de um método em C#?
Retorne uma tupla: static (int Min, int Max) Range(int[] values) e return (min, max);. Quem chama pode ler result.Min ou desconstruir com var (lo, hi) = Range(values);. Para valores que andam juntos pelo seu código, uma classe pequena ou um record é mais claro; parâmetros out são a alternativa mais antiga.
Por que recebo "An object reference is required for the non-static field, method, or property"?
Um método static como o Main chamou diretamente um método de instância. Métodos static pertencem ao tipo e não têm um objeto sobre o qual fazer a chamada. Marque o método chamado como static, ou crie um objeto antes: var app = new Program(); app.Greet();.
O que significa "not all code paths return a value"?
Erro CS0161: um método com tipo de retorno tem pelo menos um caminho que chega à chave de fechamento sem um return. Normalmente um if retorna um valor, mas não há else nem um return final depois dele. Adicione um return (ou throw) no fim do método.