Partilhar via


Métodos (Guia de Programação em C#)

Um método é um bloco de código que contém uma série de instruções. Um programa faz com que as instruções sejam executadas chamando o método e especificando quaisquer argumentos de método necessários. Em C#, cada instrução executada é executada no contexto de um método.

O Main método é o ponto de entrada para cada aplicativo C# e é chamado pelo Common Language Runtime (CLR) quando o programa é iniciado. Em um aplicativo que usa instruções de nível superior, o Main método é gerado pelo compilador e contém todas as instruções de nível superior.

Observação

Este artigo discute métodos nomeados. Para obter informações sobre funções anônimas, consulte Expressões do Lambda.

Assinaturas de método

Os métodos são declarados em uma classe, struct ou interface especificando o nível de acesso, como public ou private, modificadores opcionais, como abstract ou sealed, o valor de retorno, o nome do método e quaisquer parâmetros de método. Estas partes juntas são a assinatura do método.

Importante

O tipo de retorno de um método não faz parte da assinatura do método para fins de sobrecarga. No entanto, é uma parte da assinatura do método ao determinar a compatibilidade entre um delegado e o método para o qual este aponta.

Os parâmetros do método são colocados entre parênteses e separados por vírgulas. Parênteses vazios indicam que o método não requer parâmetros. Esta classe contém quatro métodos:

abstract class Motorcycle
{
    // Anyone can call this.
    public void StartEngine() {/* Method statements here */ }

    // Only derived classes can call this.
    protected void AddGas(int gallons) { /* Method statements here */ }

    // Derived classes can override the base class implementation.
    public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

    // Derived classes must implement this.
    public abstract double GetTopSpeed();
}

Acesso ao método

Chamar um método em um objeto é como acessar um campo. Após o nome do objeto, adicione um ponto, o nome do método e parênteses. Os argumentos são listados entre parênteses e separados por vírgulas. Os métodos da Motorcycle classe podem, portanto, ser chamados como no exemplo a seguir:

class TestMotorcycle : Motorcycle
{
    public override double GetTopSpeed()
    {
        return 108.4;
    }

    static void Main()
    {
        TestMotorcycle moto = new TestMotorcycle();

        moto.StartEngine();
        moto.AddGas(15);
        moto.Drive(5, 20);
        double speed = moto.GetTopSpeed();
        Console.WriteLine($"My top speed is {speed}");
    }
}

Parâmetros do método vs. argumentos

A definição do método especifica os nomes e tipos de quaisquer parâmetros que são necessários. Quando o código que chama invoca o método, fornece valores concretos chamados argumentos para cada parâmetro. Os argumentos devem ser compatíveis com o tipo de parâmetro, mas o nome do argumento (se houver) usado no código de chamada não precisa ser o mesmo que o parâmetro nomeado definido no método. Por exemplo:

public void Caller()
{
    int numA = 4;
    // Call with an int variable.
    int productA = Square(numA);

    int numB = 32;
    // Call with another int variable.
    int productB = Square(numB);

    // Call with an integer literal.
    int productC = Square(12);

    // Call with an expression that evaluates to int.
    productC = Square(productA * 3);
}

int Square(int i)
{
    // Store input argument in a local variable.
    int input = i;
    return input * input;
}

Passagem por referência vs. passagem por valor

Por padrão, quando uma instância de um tipo de valor é passada para um método, sua cópia é passada em vez da própria instância. Portanto, as alterações no argumento não têm efeito sobre a instância original no método de chamada. Para passar uma instância de tipo de valor por referência, utilize a "keyword" ref. Para obter mais informações, consulte Passando parâmetros Value-Type.

Quando um objeto de um tipo de referência é passado para um método, uma referência ao objeto é passada. Ou seja, o método recebe não o objeto em si, mas um argumento que indica a localização do objeto. Se você alterar um membro do objeto usando essa referência, a alteração será refletida no argumento no método de chamada, mesmo se você passar o objeto por valor.

Você cria um tipo de referência usando a palavra-chave class , como mostra o exemplo a seguir:

public class SampleRefType
{
    public int value;
}

Agora, se você passar um objeto baseado nesse tipo para um método, uma referência ao objeto será passada. O exemplo a seguir passa um objeto do tipo SampleRefType para o método ModifyObject:

public static void TestRefType()
{
    SampleRefType rt = new SampleRefType();
    rt.value = 44;
    ModifyObject(rt);
    Console.WriteLine(rt.value);
}

static void ModifyObject(SampleRefType obj)
{
    obj.value = 33;
}

O exemplo faz essencialmente a mesma coisa que o exemplo anterior, na medida em que passa um argumento por valor para um método. Mas, como um tipo de referência é usado, o resultado é diferente. A modificação feita no campo ModifyObject do parâmetro value, também altera o campo obj do argumento value no método rt. O TestRefType método exibe 33 como a saída.

Para obter mais informações sobre como passar tipos de referência por referência e por valor, consulte Passagem de Parâmetros Reference-Type e Tipos de Referência.

Valores de retorno

Os métodos podem retornar um valor para o chamador. Se o tipo de retorno (o tipo listado antes do nome do método) não for void, o método pode retornar o valor usando a instrução return. Uma instrução com a return palavra-chave seguida por um valor que corresponda ao tipo de retorno retornará esse valor para o chamador do método.

O valor pode ser devolvido ao chamador por valor ou por referência. Os valores são retornados ao chamador por referência se a palavra-chave ref for usada na assinatura do método e seguir a cada palavra-chave return. Por exemplo, a assinatura do método a seguir e a instrução return indicam que o método retorna uma variável nomeada estDistance por referência ao chamador.

public ref double GetEstimatedDistance()
{
    return ref estDistance;
}

A return palavra-chave também interrompe a execução do método. Se o tipo de retorno for void, uma return instrução sem um valor ainda será útil para interromper a execução do método. Sem a palavra-chave return , o método irá parar de ser executado quando chegar ao final do bloco de código. Os métodos com um tipo de retorno não nulo devem usar a palavra-chave return para retornar um valor. Por exemplo, esses dois métodos usam a return palavra-chave para retornar inteiros:

class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2)
    {
        return number1 + number2;
    }

    public int SquareANumber(int number)
    {
        return number * number;
    }
}

Para usar um valor retornado de um método, o método de chamada pode usar a própria chamada de método em qualquer lugar onde um valor do mesmo tipo seria suficiente. Você também pode atribuir o valor de retorno a uma variável. Por exemplo, os dois exemplos de código a seguir atingem o mesmo objetivo:

int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);

Usar uma variável local, neste caso, result, para armazenar um valor é opcional. Isso pode ajudar a legibilidade do código, ou pode ser necessário se você precisar armazenar o valor original do argumento para todo o escopo do método.

Para usar um valor retornado por referência de um método, você deve declarar uma variável local ref se pretender modificar seu valor. Por exemplo, se o Planet.GetEstimatedDistance método retorna um Double valor por referência, você pode defini-lo como uma variável local ref com código como o seguinte:

ref double distance = ref Planet.GetEstimatedDistance();

Retornar uma matriz multidimensional de um método, M, que modifica o conteúdo da matriz não é necessário se a função de chamada passou a matriz para M. Você pode retornar a matriz resultante de M para um bom estilo ou fluxo funcional de valores, mas isso não é necessário porque C# passa todos os tipos de referência por valor, e o valor de uma referência de matriz é o ponteiro para a matriz. No método M, quaisquer alterações no conteúdo da matriz são observáveis por qualquer código que tenha uma referência à matriz, conforme mostrado no exemplo a seguir:

static void Main(string[] args)
{
    int[,] matrix = new int[2, 2];
    FillMatrix(matrix);
    // matrix is now full of -1
}

public static void FillMatrix(int[,] matrix)
{
    for (int i = 0; i < matrix.GetLength(0); i++)
    {
        for (int j = 0; j < matrix.GetLength(1); j++)
        {
            matrix[i, j] = -1;
        }
    }
}

Métodos assíncronos

Usando o recurso assíncrono, você pode invocar métodos assíncronos sem usar retornos de chamada explícitos ou dividir manualmente seu código em vários métodos ou expressões lambda.

Se você marcar um método com o modificador async , poderá usar o operador await no método. Quando o controlo atinge uma expressão "await" num método assíncrono, o controlo retorna ao chamador e o progresso do método é suspenso até a conclusão da tarefa aguardada. Quando a tarefa estiver concluída, a execução poderá ser retomada no método.

Observação

Um método assíncrono retorna ao chamador quando encontra o primeiro objeto aguardado que ainda não está completo ou quando chega ao final do método assíncrono, o que ocorrer primeiro.

Um método assíncrono normalmente tem um tipo de retorno de Task<TResult>, TaskIAsyncEnumerable<T>ou void. O void tipo de retorno é usado principalmente para definir manipuladores de eventos, onde um tipo de void retorno é necessário. Um método assíncrono que retorna void não pode ser esperado, e o chamador de um método que retorna void não pode capturar exceções que o método lança. Um método assíncrono pode ter qualquer tipo de retorno semelhante a uma tarefa.

No exemplo a seguir, DelayAsync é um método assíncrono que tem um tipo de retorno de Task<TResult>. DelayAsync tem uma return declaração que retorna um inteiro. Portanto, a declaração de método de DelayAsync deve ter um tipo de retorno de Task<int>. Como o tipo de retorno é Task<int>, a avaliação da await expressão em DoSomethingAsync produz um inteiro como demonstra a seguinte instrução: int result = await delayTask.

O Main método é um exemplo de um método assíncrono que tem um tipo de retorno de Task. Vai para o método DoSomethingAsync, e porque é expresso com uma única linha, pode omitir as palavras-chave async e await. Como DoSomethingAsync é um método assíncrono, a tarefa da chamada para DoSomethingAsync deve ser aguardada, como mostra a instrução a seguir: await DoSomethingAsync();.

class Program
{
    static Task Main() => DoSomethingAsync();

    static async Task DoSomethingAsync()
    {
        Task<int> delayTask = DelayAsync();
        int result = await delayTask;

        // The previous two statements may be combined into
        // the following statement.
        //int result = await DelayAsync();

        Console.WriteLine($"Result: {result}");
    }

    static async Task<int> DelayAsync()
    {
        await Task.Delay(100);
        return 5;
    }
}
// Example output:
//   Result: 5

Um método assíncrono não pode declarar nenhum parâmetro ref ou out , mas pode chamar métodos que tenham esses parâmetros.

Para obter mais informações sobre métodos assíncronos, consulte Programação assíncrona com async e await e Tipos de retorno Async.

Definições de corpo de expressão

É comum haver definições de método que simplesmente retornam imediatamente com o resultado de uma expressão, ou que têm uma única instrução como o corpo do método. Há um atalho de sintaxe para definir tais métodos usando =>:

public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);

Se o método retorna void ou é um método assíncrono, então o corpo do método deve ser uma expressão de instrução (igual ao lambdas). Para propriedades e indexadores, eles devem ser somente leitura e você não usa a get palavra-chave accessor.

Iteradores

Um iterador executa uma iteração personalizada sobre uma coleção, como uma lista ou uma matriz. Um iterador usa a instrução yield return para devolver cada elemento, um por vez. Quando uma yield return instrução é alcançada, o local atual no código é lembrado. A execução é reiniciada a partir desse local quando o iterador é chamado na próxima vez.

Você chama um iterador do código do cliente usando uma instrução foreach .

O tipo de retorno de um iterador pode ser IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumerator, ou IEnumerator<T>.

Para obter mais informações, consulte Iteradores.

Especificação da linguagem C#

Para obter mais informações, consulte a Especificação da Linguagem C# . A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#.

Ver também