Métodos 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.
Nota
Este tópico 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 , class
record
ou struct
especificando:
- Um nível de acesso opcional, como
public
ouprivate
. A predefinição éprivate
. - Modificadores opcionais, como
abstract
ousealed
. - O valor de retorno, ou
void
se o método não tiver nenhum. - O nome do método.
- Qualquer parâmetro de método. 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.
Essas partes juntas formam 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.
O exemplo a seguir define uma classe chamada Motorcycle
que contém cinco métodos:
namespace MotorCycleExample
{
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 can override the base class implementation.
public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }
// Derived classes must implement this.
public abstract double GetTopSpeed();
}
A Motorcycle
classe inclui um método sobrecarregado, Drive
. Dois métodos têm o mesmo nome, mas são diferenciados por seus tipos de parâmetros.
Invocação do método
Os métodos podem ser de instância ou estáticos. Você deve instanciar um objeto para invocar um método de instância nessa instância; Um método de instância opera nessa instância e em seus dados. Você invoca um método estático fazendo referência ao nome do tipo ao qual o método pertence; Os métodos estáticos não operam em dados de instância. Tentar chamar um método estático através de uma instância de objeto gera um erro de compilador.
Chamar um método é como acessar um campo. Após o nome do objeto (se você estiver chamando um método de instância) ou o nome do tipo (se estiver chamando um static
método), adicione um ponto, o nome do método e parênteses. Os argumentos são listados entre parênteses e separados por vírgulas.
A definição do método especifica os nomes e tipos de quaisquer parâmetros que são necessários. Quando um chamador invoca 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 for usado no código de chamada, não precisa ser o mesmo que o parâmetro nomeado definido no método. No exemplo a seguir, o Square
método inclui um único parâmetro do tipo int
chamado i. A primeira chamada de método passa ao Square
método uma variável do tipo int
chamada num, a segunda, uma constante numérica e a terceira, uma expressão.
public static class SquareExample
{
public static void Main()
{
// Call with an int variable.
int num = 4;
int productA = Square(num);
// Call with an integer literal.
int productB = Square(12);
// Call with an expression that evaluates to int.
int productC = Square(productA * 3);
}
static int Square(int i)
{
// Store input argument in a local variable.
int input = i;
return input * input;
}
}
A forma mais comum de invocação de método usava argumentos posicionais; ele fornece argumentos na mesma ordem que os parâmetros do método. Os métodos da Motorcycle
classe podem, portanto, ser chamados como no exemplo a seguir. A chamada para o Drive
método, por exemplo, inclui dois argumentos que correspondem aos dois parâmetros na sintaxe do método. O primeiro torna-se o valor do miles
parâmetro. O segundo torna-se o valor do speed
parâmetro.
class TestMotorcycle : Motorcycle
{
public override double GetTopSpeed() => 108.4;
static void Main()
{
var moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
_ = moto.Drive(5, 20);
double speed = moto.GetTopSpeed();
Console.WriteLine("My top speed is {0}", speed);
}
}
Você também pode usar argumentos nomeados em vez de argumentos posicionais ao invocar um método. Ao usar argumentos nomeados, você especifica o nome do parâmetro seguido por dois pontos (":") e o argumento. Os argumentos para o método podem aparecer em qualquer ordem, desde que todos os argumentos necessários estejam presentes. O exemplo a seguir usa argumentos nomeados para invocar o TestMotorcycle.Drive
método. Neste exemplo, os argumentos nomeados são passados na ordem oposta da lista de parâmetros do método.
namespace NamedMotorCycle;
class TestMotorcycle : Motorcycle
{
public override int Drive(int miles, int speed) =>
(int)Math.Round((double)miles / speed, 0);
public override double GetTopSpeed() => 108.4;
static void Main()
{
var moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
int travelTime = moto.Drive(miles: 170, speed: 60);
Console.WriteLine("Travel time: approx. {0} hours", travelTime);
}
}
// The example displays the following output:
// Travel time: approx. 3 hours
Você pode invocar um método usando argumentos posicionais e argumentos nomeados. No entanto, os argumentos posicionais só podem seguir os argumentos nomeados quando os argumentos nomeados estiverem nas posições corretas. O exemplo a seguir invoca o TestMotorcycle.Drive
método do exemplo anterior usando um argumento posicional e um argumento nomeado.
int travelTime = moto.Drive(170, speed: 55);
Métodos herdados e substituídos
Além dos membros que são explicitamente definidos em um tipo, um tipo herda membros definidos em suas classes base. Como todos os tipos no sistema de tipos gerenciados herdam direta ou indiretamente da Object classe, todos os tipos herdam seus membros, como Equals(Object), GetType()e ToString(). O exemplo a seguir define uma Person
classe, instancia dois Person
objetos e chama o Person.Equals
método para determinar se os dois objetos são iguais. O Equals
método, no entanto, não é definido na Person
classe, é herdado do Object.
public class Person
{
public string FirstName = default!;
}
public static class ClassTypeExample
{
public static void Main()
{
Person p1 = new() { FirstName = "John" };
Person p2 = new() { FirstName = "John" };
Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
}
}
// The example displays the following output:
// p1 = p2: False
Os tipos podem substituir membros herdados usando a override
palavra-chave e fornecendo uma implementação para o método substituído. A assinatura do método deve ser a mesma que o método substituído. O exemplo a seguir é como o anterior, exceto que ele substitui o Equals(Object) método. (Ele também substitui o GetHashCode() método, uma vez que os dois métodos se destinam a fornecer resultados consistentes.)
namespace methods;
public class Person
{
public string FirstName = default!;
public override bool Equals(object? obj) =>
obj is Person p2 &&
FirstName.Equals(p2.FirstName);
public override int GetHashCode() => FirstName.GetHashCode();
}
public static class Example
{
public static void Main()
{
Person p1 = new() { FirstName = "John" };
Person p2 = new() { FirstName = "John" };
Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
}
}
// The example displays the following output:
// p1 = p2: True
Parâmetros de passagem
Os tipos em C# são tipos de valor ou tipos de referência. Para obter uma lista de tipos de valores internos, consulte Tipos. Por padrão, os tipos de valor e os tipos de referência são passados por valor para um método.
Passando parâmetros por valor
Quando um tipo de valor é passado para um método por valor, uma cópia do objeto em vez do próprio objeto é passada para o método. Portanto, as alterações no objeto no método chamado não têm efeito sobre o objeto original quando o controle retorna ao chamador.
O exemplo a seguir passa um tipo de valor para um método por valor, e o método chamado tenta alterar o valor do tipo de valor. Ele define uma variável do tipo int
, que é um tipo de valor, inicializa seu valor para 20 e o passa para um método chamado ModifyValue
que altera o valor da variável para 30. Quando o método retorna, no entanto, o valor da variável permanece inalterado.
public static class ByValueExample
{
public static void Main()
{
var value = 20;
Console.WriteLine("In Main, value = {0}", value);
ModifyValue(value);
Console.WriteLine("Back in Main, value = {0}", value);
}
static void ModifyValue(int i)
{
i = 30;
Console.WriteLine("In ModifyValue, parameter value = {0}", i);
return;
}
}
// The example displays the following output:
// In Main, value = 20
// In ModifyValue, parameter value = 30
// Back in Main, value = 20
Quando um objeto de um tipo de referência é passado para um método por valor, uma referência ao objeto é passada por valor. 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 objeto quando o controle retornar ao método de chamada. No entanto, a substituição do objeto passado para o método não tem efeito sobre o objeto original quando o controle retorna ao chamador.
O exemplo a seguir define uma classe (que é um tipo de referência) chamada SampleRefType
. Ele instancia um SampleRefType
objeto, atribui 44 ao seu value
campo e passa o objeto para o ModifyObject
método. Este exemplo faz essencialmente a mesma coisa que o exemplo anterior: ele 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 ModifyObject
obj.value
campo também altera o value
campo do argumento, rt
no Main
método para 33, como mostra a saída do exemplo.
public class SampleRefType
{
public int value;
}
public static class ByRefTypeExample
{
public static void Main()
{
var rt = new SampleRefType { value = 44 };
ModifyObject(rt);
Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj) => obj.value = 33;
}
Passagem de parâmetros por referência
Você passa um parâmetro por referência quando deseja alterar o valor de um argumento em um método e deseja refletir essa alteração quando o controle retorna ao método de chamada. Para passar um parâmetro por referência, use a ref
palavra-chave ou out
. Você também pode passar um valor por referência para evitar cópias, mas ainda assim impedir modificações usando a in
palavra-chave.
O exemplo a seguir é idêntico ao anterior, exceto que o valor é passado por referência ao ModifyValue
método. Quando o valor do parâmetro é modificado no ModifyValue
método, a alteração no valor é refletida quando o controle retorna ao chamador.
public static class ByRefExample
{
public static void Main()
{
var value = 20;
Console.WriteLine("In Main, value = {0}", value);
ModifyValue(ref value);
Console.WriteLine("Back in Main, value = {0}", value);
}
private static void ModifyValue(ref int i)
{
i = 30;
Console.WriteLine("In ModifyValue, parameter value = {0}", i);
return;
}
}
// The example displays the following output:
// In Main, value = 20
// In ModifyValue, parameter value = 30
// Back in Main, value = 30
Um padrão comum que usa parâmetros ref envolve a troca dos valores das variáveis. Você passa duas variáveis para um método por referência, e o método troca seu conteúdo. O exemplo a seguir troca valores inteiros.
public static class RefSwapExample
{
static void Main()
{
int i = 2, j = 3;
Console.WriteLine("i = {0} j = {1}", i, j);
Swap(ref i, ref j);
Console.WriteLine("i = {0} j = {1}", i, j);
}
static void Swap(ref int x, ref int y) =>
(y, x) = (x, y);
}
// The example displays the following output:
// i = 2 j = 3
// i = 3 j = 2
Passar um parâmetro de tipo de referência permite alterar o valor da própria referência, em vez do valor de seus elementos ou campos individuais.
Coleções de parâmetros
Às vezes, o requisito de que você especifique o número exato de argumentos para o seu método é restritivo. Usando a params
palavra-chave para indicar que um parâmetro é uma coleção de parâmetros, você permite que seu método seja chamado com um número variável de argumentos. O parâmetro marcado com a params
palavra-chave deve ser um tipo de coleção e deve ser o último parâmetro na lista de parâmetros do método.
Um chamador pode então invocar o método de quatro maneiras para o params
parâmetro:
- Passando uma coleção do tipo apropriado que contém o número desejado de elementos. O exemplo usa uma expressão de coleção para que o compilador crie um tipo de coleção apropriado.
- Passando uma lista separada por vírgulas de argumentos individuais do tipo apropriado para o método. O compilador cria o tipo de coleção apropriado.
- Passando
null
. - Não fornecendo um argumento para a coleção de parâmetros.
O exemplo a seguir define um método chamado GetVowels
que retorna todas as vogais de uma coleção de parâmetros. O Main
método ilustra todas as quatro maneiras de invocar o método. Os chamadores não são obrigados a fornecer argumentos para parâmetros que incluam o params
modificador. Nesse caso, o parâmetro é uma coleção vazia.
static class ParamsExample
{
static void Main()
{
string fromArray = GetVowels(["apple", "banana", "pear"]);
Console.WriteLine($"Vowels from collection expression: '{fromArray}'");
string fromMultipleArguments = GetVowels("apple", "banana", "pear");
Console.WriteLine($"Vowels from multiple arguments: '{fromMultipleArguments}'");
string fromNull = GetVowels(null);
Console.WriteLine($"Vowels from null: '{fromNull}'");
string fromNoValue = GetVowels();
Console.WriteLine($"Vowels from no value: '{fromNoValue}'");
}
static string GetVowels(params IEnumerable<string>? input)
{
if (input == null || !input.Any())
{
return string.Empty;
}
char[] vowels = ['A', 'E', 'I', 'O', 'U'];
return string.Concat(
input.SelectMany(
word => word.Where(letter => vowels.Contains(char.ToUpper(letter)))));
}
}
// The example displays the following output:
// Vowels from array: 'aeaaaea'
// Vowels from multiple arguments: 'aeaaaea'
// Vowels from null: ''
// Vowels from no value: ''
Antes do C# 13, o params
modificador só podia ser usado com uma matriz unidimensional.
Parâmetros e argumentos opcionais
Uma definição de método pode especificar que seus parâmetros são necessários ou que eles são opcionais. Por padrão, os parâmetros são necessários. Os parâmetros opcionais são especificados incluindo o valor padrão do parâmetro na definição do método. Quando o método é chamado, se nenhum argumento for fornecido para um parâmetro opcional, o valor padrão será usado.
Você atribui o valor padrão do parâmetro com um dos seguintes tipos de expressões:
Uma constante, como uma cadeia de caracteres literal ou um número.
Uma expressão do formulário
default(SomeType)
, ondeSomeType
pode ser um tipo de valor ou um tipo de referência. Se for um tipo de referência, é efetivamente o mesmo que especificarnull
. Você pode usar odefault
literal, pois o compilador pode inferir o tipo a partir da declaração do parâmetro.Uma expressão do formulário
new ValType()
, ondeValType
é um tipo de valor. Esta expressão invoca o construtor implícito sem parâmetros do tipo de valor, que não é um membro real do tipo.Nota
Em C# 10 e posteriores, quando uma expressão do formulário
new ValType()
invoca o construtor sem parâmetros explicitamente definido de um tipo de valor, o compilador gera um erro, pois o valor do parâmetro padrão deve ser uma constante de tempo de compilação. Use adefault(ValType)
expressão ou odefault
literal para fornecer o valor do parâmetro padrão. Para obter mais informações sobre construtores sem parâmetros, consulte a seção Inicialização de struct e valores padrão do artigo Tipos de estrutura.
Se um método incluir parâmetros obrigatórios e opcionais, os parâmetros opcionais serão definidos no final da lista de parâmetros, após todos os parâmetros necessários.
O exemplo a seguir define um método, ExampleMethod
, que tem um parâmetro obrigatório e dois opcionais.
public class Options
{
public void ExampleMethod(int required, int optionalInt = default,
string? description = default)
{
var msg = $"{description ?? "N/A"}: {required} + {optionalInt} = {required + optionalInt}";
Console.WriteLine(msg);
}
}
O chamador deve fornecer um argumento para todos os parâmetros opcionais até o último parâmetro opcional para o qual um argumento é fornecido. ExampleMethod
No método, por exemplo, se o chamador fornece um argumento para o description
parâmetro, ele também deve fornecer um para o optionalInt
parâmetro. opt.ExampleMethod(2, 2, "Addition of 2 and 2");
é uma chamada de método válida; opt.ExampleMethod(2, , "Addition of 2 and 0");
gera um erro de compilador "Argumento ausente".
Se um método for chamado usando argumentos nomeados ou uma combinação de argumentos posicionais e nomeados, o chamador poderá omitir quaisquer argumentos que sigam o último argumento posicional na chamada do método.
O exemplo a seguir chama o ExampleMethod
método três vezes. As duas primeiras chamadas de método usam argumentos posicionais. O primeiro omite ambos os argumentos opcionais, enquanto o segundo omite o último argumento. A terceira chamada de método fornece um argumento posicional para o parâmetro necessário, mas usa um argumento nomeado para fornecer um valor para o description
parâmetro enquanto omite o optionalInt
argumento.
public static class OptionsExample
{
public static void Main()
{
var opt = new Options();
opt.ExampleMethod(10);
opt.ExampleMethod(10, 2);
opt.ExampleMethod(12, description: "Addition with zero:");
}
}
// The example displays the following output:
// N/A: 10 + 0 = 10
// N/A: 10 + 2 = 12
// Addition with zero:: 12 + 0 = 12
O uso de parâmetros opcionais afeta a resolução de sobrecarga, ou a maneira como o compilador C# determina qual sobrecarga invocar para uma chamada de método, da seguinte maneira:
- Um método, indexador ou construtor é um candidato para execução se cada um de seus parâmetros corresponder por nome ou por posição a um único argumento, e esse argumento pode ser convertido para o tipo do parâmetro.
- Se mais de um candidato for encontrado, as regras de resolução de sobrecarga para conversões preferenciais serão aplicadas aos argumentos explicitamente especificados. Os argumentos omitidos para parâmetros opcionais são ignorados.
- Se dois candidatos forem considerados igualmente bons, a preferência vai para um candidato que não tenha parâmetros opcionais para os quais os argumentos foram omitidos na chamada.
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 void
for , o método pode retornar o valor usando a palavra-chave return
. Uma instrução com a return
palavra-chave seguida por uma variável, constante ou expressão que corresponde ao tipo de retorno retorna esse valor para o chamador do método. Os métodos com um tipo de retorno nonvoid são necessários para usar a return
palavra-chave para retornar um valor. 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 return
palavra-chave, o método para de ser executado quando atinge o final do bloco de código.
Por exemplo, esses dois métodos usam a return
palavra-chave para retornar inteiros:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2) =>
number1 + number2;
public int SquareANumber(int number) =>
number * number;
}
Os exemplos acima são membros com corpo de expressão. Os membros com corpo de expressão retornam o valor retornado pela expressão.
Você também pode optar por definir seus métodos com um corpo de instrução e uma return
instrução:
class SimpleMathExtnsion
{
public int DivideTwoNumbers(int number1, int number2)
{
return number1 / number2;
}
}
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 três 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);
result = obj2.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);
Às vezes, você deseja que seu método retorne mais de um único valor. Você usa tipos de tupla e literais de tupla para retornar vários valores. O tipo de tupla define os tipos de dados dos elementos da tupla. Os literais de tupla fornecem os valores reais da tupla retornada. No exemplo a seguir, (string, string, string, int)
define o tipo de tupla GetPersonalInfo
retornado pelo método. A expressão (per.FirstName, per.MiddleName, per.LastName, per.Age)
é a tupla literal, o método retorna o primeiro, o nome do meio e a família, juntamente com a idade, de um PersonInfo
objeto.
public (string, string, string, int) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
O chamador pode então consumir a tupla retornada usando o seguinte código:
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.Item1} {person.Item3}: age = {person.Item4}");
Os nomes também podem ser atribuídos aos elementos de tupla na definição de tipo de tupla. O exemplo a seguir mostra uma versão alternativa do GetPersonalInfo
método que usa elementos nomeados:
public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
A chamada anterior para o GetPersonalInfo
método pode então ser modificada da seguinte forma:
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.FName} {person.LName}: age = {person.Age}");
Se um método usa uma matriz como parâmetro e modifica o valor de elementos individuais, não é necessário que o método retorne a matriz. 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 exemplo a seguir, as alterações no conteúdo da values
matriz que são feitas no DoubleValues
método são observáveis por qualquer código que tenha uma referência à matriz.
public static class ArrayValueExample
{
static void Main()
{
int[] values = [2, 4, 6, 8];
DoubleValues(values);
foreach (var value in values)
{
Console.Write("{0} ", value);
}
}
public static void DoubleValues(int[] arr)
{
for (var ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
{
arr[ctr] *= 2;
}
}
}
// The example displays the following output:
// 4 8 12 16
Métodos de extensão
Normalmente, há duas maneiras de adicionar um método a um tipo existente:
- Modifique o código-fonte desse tipo. Modificar a origem cria uma alteração de quebra se você também adicionar campos de dados privados para dar suporte ao método.
- Defina o novo método em uma classe derivada. Um método não pode ser adicionado dessa maneira usando herança para outros tipos, como estruturas e enumerações. Também não pode ser usado para "adicionar" um método a uma classe selada.
Os métodos de extensão permitem "adicionar" um método a um tipo existente sem modificar o próprio tipo ou implementar o novo método em um tipo herdado. O método de extensão também não precisa residir no mesmo assembly que o tipo que ele estende. Você chama um método de extensão como se fosse um membro definido de um tipo.
Para obter mais informações, consulte Métodos de extensão.
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 await
expressão no método assíncrono, o controle retorna ao chamador se a tarefa aguardada não for concluída e o progresso no método com a await
palavra-chave é suspenso até que a tarefa esperada 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>, Task, IAsyncEnumerable<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 uma instrução return que retorna um inteiro. Como é um método assíncrono, sua declaração de método 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 instrução a seguir int result = await delayTask
.
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 in, 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.
Membros com corpo de expressão
É comum ter definições de método que 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 esses 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, 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 é lembrado para que o chamador possa solicitar o próximo elemento na sequência.
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.