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.

Nota

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

Um tipo de retorno de um método não faz parte da assinatura do método para fins de sobrecarga do método. No entanto, faz parte da assinatura do método ao determinar a compatibilidade entre um delegado e o método para o qual ele 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 {0}", 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. Ao chamar o código chama o método, ele 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, use a ref palavra-chave. Para obter mais informações, consulte Passando parâmetros de tipo de valor.

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 que é feita no ModifyObjectvalue campo do parâmetro, obj, também altera o value campo do argumento, rtno TestRefType método. 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 Passando parâmetros de tipo de referência 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 voidfor , o método pode retornar o valor usando a return instrução. 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 ref palavra-chave for usada na assinatura do método e seguir cada return palavra-chave. 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 vazio são necessários para usar a return palavra-chave 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 controle atinge uma expressão await no método async, o controle retorna ao chamador e o progresso no método é suspenso até que a tarefa aguardada seja concluída. Quando a tarefa estiver concluída, a execução poderá ser retomada no método.

Nota

Um método assíncrono retorna ao chamador quando encontra o primeiro objeto aguardado que ainda não está completo ou 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 aguardado, e o chamador de um método de retorno de vazio 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 instruçã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. Ele vai para o DoSomethingAsync método, e porque é expresso com uma única linha, ele pode omitir as async palavras-chave e await . Como DoSomethingAsync é um método assíncrono, a tarefa para DoSomethingAsync a chamada 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 tipos de retorno async e await e Async.

Definições do corpo da 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 retornar cada elemento, um de cada 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#.

Consulte também