Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Você usa vários operadores e expressões para acessar um membro de um tipo. Os operadores de acesso de membro incluem acesso de membro (.), elemento de matriz ou acesso de indexador ([]), indexação a partir do fim (^), intervalo (..), operadores condicionais nulos (?. e ?[]) e invocação de método (()). Esses operadores incluem os operadores null-conditional member access (?.) e indexer access (?[]).
-
.(acesso de membro): Acede a um membro de um namespace ou de um tipo. -
[](acesso a elemento de array ou indexador): Acede a um elemento de array ou a um indexador de tipos. -
?.e?[](operadores nulos-condicionais): Realizar uma operação de acesso a membros ou elementos apenas se um operando for não nulo. -
()(invocação): Chamar um método acedido ou invocar um delegado. -
^(índice a partir do fim): Indique que a posição do elemento é a partir do fim de uma sequência. -
..(alcance): Especifique um intervalo de índices que pode usar para obter um intervalo de elementos de sequência.
A referência da linguagem C# documenta a versão mais recentemente lançada da linguagem C#. Contém também documentação inicial para funcionalidades em versões preliminares públicas para a próxima versão da linguagem.
A documentação identifica qualquer funcionalidade introduzida pela primeira vez nas últimas três versões da língua ou em pré-visualizações públicas atuais.
Sugestão
Para saber quando uma funcionalidade foi introduzida pela primeira vez em C#, consulte o artigo sobre o histórico de versões da linguagem C#.
Expressão de acesso a membro .
Use o . token para aceder a um membro de um namespace ou a um tipo, como demonstram os exemplos seguintes:
- Use
.para aceder a um namespace aninhado dentro de outro namespace, como mostra o seguinte exemplo de uma diretivausingusing:
using System.Collections.Generic;
- Use
.para formar um nome qualificado para aceder a um tipo dentro de um espaço de nomes, como mostra o código a seguir.
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];
Use uma using diretiva para tornar opcional o uso de nomes qualificados.
- Use
.para aceder a membros do tipo, estáticos e não estáticos, como demonstra o código a seguir:
List<double> constants =
[
Math.PI,
Math.E
];
Console.WriteLine($"{constants.Count} values to show:");
Console.WriteLine(string.Join(", ", constants));
// Output:
// 2 values to show:
// 3.14159265358979, 2.71828182845905
Também pode usar . para aceder a um membro da extensão.
Operador indexador []
Parênteses quadrados, [], normalmente acedem a elementos de array, indexador ou ponteiro. Começando com C# 12, [] inclui uma expressão de coleção.
Acesso ao array
O exemplo a seguir demonstra como acessar elementos de matriz:
int[] fib = new int[10];
fib[0] = fib[1] = 1;
for (int i = 2; i < fib.Length; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
Console.WriteLine(fib[fib.Length - 1]); // output: 55
double[,] matrix = new double[2,2];
matrix[0,0] = 1.0;
matrix[0,1] = 2.0;
matrix[1,0] = matrix[1,1] = 3.0;
var determinant = matrix[0,0] * matrix[1,1] - matrix[1,0] * matrix[0,1];
Console.WriteLine(determinant); // output: -3
Se um índice de array estiver fora dos limites da dimensão correspondente de um array, o tempo de execução lança um IndexOutOfRangeException.
Como mostra o exemplo anterior, você também usa colchetes quando declara um tipo de matriz ou instancia uma instância de matriz.
Para obter mais informações sobre matrizes, consulte Matrizes.
Acesso ao indexador
O exemplo a seguir usa o tipo .NET Dictionary<TKey,TValue> para demonstrar o acesso do indexador:
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Os indexadores permitem indexar instâncias de um tipo definido pelo utilizador de forma semelhante à indexação de arrays. Ao contrário dos índices de matriz, que devem ser inteiros, os parâmetros do indexador podem ser declarados como sendo de qualquer tipo.
Para obter mais informações sobre indexadores, consulte Indexadores.
Outros usos de []
Para obter informações sobre o operador de acesso ao elemento de ponteiro [], consulte a seção do artigo Operadores relacionados ao ponteiro. Para obter informações sobre expressões de coleção, consulte o artigo de expressões de coleção.
Você também usa colchetes para especificar atributos:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
Além disso, utilize colchetes quadrados para designar padrões de lista para uso em correspondência ou testes de moldes.
arr is ([1, 2, ..])
//Specifies that an array starts with (1, 2)
Operadores condicionais nulos ?. e ?[]
Um operador nulo-condicional aplica uma operação de acesso a membro (?.) ou de acesso a elemento (?[]) ao seu operando apenas se esse operando for avaliado como não-nulo. Caso contrário, ele retornará null. Por outras palavras:
Se
aavalia paranull, o resultado dea?.xoua?[x]énull.Se
aé avaliado como não-nulo, o resultado dea?.xoua?[x]é o mesmo que o resultado dea.xoua[x], respectivamente.Nota
Se
a.xoua[x]lança uma exceção,a?.xoua?[x]lança a mesma exceção para não-nuloa. Por exemplo, seaé uma instância de array não nula exestá fora dos limites dea,a?[x]lança um IndexOutOfRangeException.
Os operadores condicionais nulos são curto-circuitos. Ou seja, se uma operação numa cadeia de acesso a membros ou elementos condicionais retornar null, o restante da cadeia não será executado. No exemplo a seguir, C não é avaliado se A avalia para null e C não é avaliado se A ou B avalia para null:
A?.B?.Do(C);
A?.B?[C];
Se A puder ser null, mas B e C não seriam null se A não fosse null, só precisa aplicar o operador de condição nula a A:
A?.B.C();
No exemplo anterior, B não é avaliado e C() não é chamado se A for nulo. No entanto, se o acesso do membro encadeado for interrompido, por exemplo, entre parênteses como no (A?.B).C(), o curto-circuito não acontece.
Os exemplos a seguir demonstram o uso dos ?. operadores e ?[] :
double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}
var sum1 = SumNumbers(null, 0);
Console.WriteLine(sum1); // output: NaN
List<double[]?> numberSets =
[
[1.0, 2.0, 3.0],
null
];
var sum2 = SumNumbers(numberSets, 0);
Console.WriteLine(sum2); // output: 6
var sum3 = SumNumbers(numberSets, 1);
Console.WriteLine(sum3); // output: NaN
namespace MemberAccessOperators2;
public static class NullConditionalShortCircuiting
{
public static void Main()
{
Person? person = null;
person?.Name.Write(); // no output: Write() is not called due to short-circuit.
try
{
(person?.Name).Write();
}
catch (NullReferenceException)
{
Console.WriteLine("NullReferenceException");
}; // output: NullReferenceException
}
}
public class Person
{
public required FullName Name { get; set; }
}
public class FullName
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
public void Write() => Console.WriteLine($"{FirstName} {LastName}");
}
O primeiro exemplo mencionado também utiliza o operador de coalescência nula ?? para especificar uma expressão alternativa a ser avaliada caso o resultado de uma operação condicional nula seja null.
Se a.x ou a[x] é de um tipo Tde valor não anulável , a?.x ou a?[x] é do tipoT?de valor anulável correspondente . Se precisar de uma expressão do tipo T, aplique o operador de coalescência nula ?? a uma expressão condicional nula, como no exemplo a seguir:
int GetSumOfFirstTwoOrDefault(int[]? numbers)
{
if ((numbers?.Length ?? 0) < 2)
{
return 0;
}
return numbers[0] + numbers[1];
}
Console.WriteLine(GetSumOfFirstTwoOrDefault(null)); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([])); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([3, 4, 5])); // output: 7
No exemplo anterior, se você não usar o ?? operador, numbers?.Length < 2 avalia quando falsenumbers é null.
Nota
O ?. operador avalia o seu operando esquerdo apenas uma vez, garantindo que ele não possa ser alterado para null após ser verificado como não-nulo.
A partir do C# 14, a atribuição é permitida com uma expressão de acesso condicional nula (?. e ?[]) em tipos de referência. Por exemplo, consulte o seguinte método:
person?.FirstName = "Scott";
messages?[5] = "five";
O exemplo anterior mostra a atribuição a uma propriedade e a um elemento indexado num tipo de referência que pode ser nulo. Um comportamento importante para esta tarefa é que a expressão no lado direito do = é avaliada somente quando se sabe que o lado esquerdo não é nulo. Por exemplo, no código a seguir, a função GenerateNextIndex é chamada somente quando a values matriz não é nula. Se a values matriz for nula, GenerateNextIndex não será chamada:
values?[2] = GenerateNextIndex();
int GenerateNextIndex() => index++;
Em outras palavras, o código anterior é equivalente ao código a seguir usando uma if instrução para a verificação nula:
if (values is not null)
{
values[2] = GenerateNextIndex();
}
Além da atribuição, qualquer forma de atribuição composta, como += ou -=, é permitida. No entanto, incremento (++) e decréscimo (--) não são permitidos.
Esse aprimoramento não classifica uma expressão condicional nula como uma variável. Ele não pode ser ref atribuído, nem pode ser atribuído a uma ref variável ou passado para um método como um ref ou out argumento.
Invocação de delegado seguro para threads
Use o ?. operador para verificar se um delegado não é nulo e invoque-o de forma segura para thread (por exemplo, quando levantar um evento), como mostra o seguinte código:
PropertyChanged?.Invoke(…)
Esse código é equivalente ao seguinte código:
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
O exemplo anterior é uma forma segura para threads de garantir que apenas um handler não nulo seja invocado. Como as instâncias delegadas são imutáveis, nenhum thread pode alterar o objeto referenciado handler pela variável local. Em particular, se o código executado por outro thread cancelar a PropertyChanged inscrição do evento e PropertyChanged se tornar null antes handler é invocado, o objeto referenciado por handler permanece inalterado.
Expressão de invocação ()
Utilize os parênteses, (), para chamar um método ou invocar um delegado.
O código a seguir demonstra como chamar um método, com ou sem argumentos, e invocar um delegado:
Action<int> display = s => Console.WriteLine(s);
List<int> numbers =
[
10,
17
];
display(numbers.Count); // output: 2
numbers.Clear();
display(numbers.Count); // output: 0
Também usas parênteses quando invocas um construtor usando o new operador.
Outros usos de ()
Você também usa parênteses para ajustar a ordem na qual avaliar operações em uma expressão. Para obter mais informações, consulte operadores C#.
As expressões de transmissão, que executam conversões de tipo explícitas, também usam parênteses.
Índice do operador final ^
Pode usar operadores de índice e intervalo com um tipo que seja contável. Um tipo enumerável tem uma int propriedade chamada ou CountLength com um acessório acessível get . As expressões de coleção também dependem de tipos contáveis .
Nota
Matrizes unidimensionais são contáveis. Matrizes multidimensionais não são. Não podes usar os ^ operadores e .. (alcance) em arrays multidimensionais.
O ^ operador indica a posição do elemento a partir do final de uma sequência. Para uma sequência de comprimento length, ^n aponta para o elemento com deslocamento length - n desde o início de uma sequência. Por exemplo, ^1 aponta para o último elemento de uma sequência e ^length aponta para o primeiro elemento de uma sequência.
int[] xs = [0, 10, 20, 30, 40];
int last = xs[^1];
Console.WriteLine(last); // output: 40
List<string> lines = ["one", "two", "three", "four"];
string prelast = lines[^2];
Console.WriteLine(prelast); // output: three
string word = "Twenty";
Index toFirst = ^word.Length;
char first = word[toFirst];
Console.WriteLine(first); // output: T
Como mostra o exemplo anterior, a expressão ^e é do tipo System.Index. Na expressão ^e, o resultado de e deve ser implicitamente conversível para int.
Você também pode usar o ^ operador com o operador de intervalo para criar um intervalo de índices. Para obter mais informações, consulte Índices e intervalos.
A partir de C# 13, pode usar o Índice do operador final, ^, num inicializador de objetos.
Operador de intervalo ..
O .. operador especifica o início e o fim de um intervalo de índices como seus operandos. O operando esquerdo é um início inclusivo de um intervalo. O operando à direita é um fim exclusivo de um intervalo. Qualquer um dos operandos pode ser um índice desde o início ou do fim de uma sequência, como mostra o exemplo seguinte:
int[] numbers = [0, 10, 20, 30, 40, 50];
int start = 1;
int amountToTake = 3;
int[] subset = numbers[start..(start + amountToTake)];
Display(subset); // output: 10 20 30
int margin = 1;
int[] inner = numbers[margin..^margin];
Display(inner); // output: 10 20 30 40
string line = "one two three";
int amountToTakeFromEnd = 5;
Range endIndices = ^amountToTakeFromEnd..^0;
string end = line[endIndices];
Console.WriteLine(end); // output: three
void Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
Como mostra o exemplo anterior, a expressão ^e é do tipo System.Index. Na expressão , os resultados de e devem ser implicitamente convertíveis para ou .
Importante
Conversões implícitas de int para Index lançam um ArgumentOutOfRangeException quando o valor é negativo.
Pode omitir qualquer um dos operandos do operador .. para obter um intervalo sem limite:
a..é equivalente aa..^0a..é equivalente aa..^0a..é equivalente aa..^0
int[] numbers = [0, 10, 20, 30, 40, 50];
int amountToDrop = numbers.Length / 2;
int[] rightHalf = numbers[amountToDrop..];
Display(rightHalf); // output: 30 40 50
int[] leftHalf = numbers[..^amountToDrop];
Display(leftHalf); // output: 0 10 20
int[] all = numbers[..];
Display(all); // output: 0 10 20 30 40 50
void Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
A tabela a seguir mostra várias maneiras de expressar intervalos de coleção:
| Expressão do operador de intervalo | Descrição |
|---|---|
.. |
Todos os valores na coleção. |
..end |
Valores desde o começo até a end exclusivo. |
start.. |
Valores desde o start inclusive até ao fim. |
start..end |
Valores de start inclusive a end exclusivo. |
^start.. |
Valores desde o start inclusive até ao final, contando a partir do final. |
..^end |
Valores desde o início até ao end, contados exclusivamente a partir do fim. |
start..^end |
Valores de start inclusivamente a end exclusivamente, contando a partir do final. |
^start..^end |
Valores de start inclusivos a end exclusivos, ambos contados a partir do final. |
O exemplo a seguir demonstra o efeito do uso de todos os intervalos apresentados na tabela anterior:
int[] oneThroughTen =
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
];
Write(oneThroughTen, ..);
Write(oneThroughTen, ..3);
Write(oneThroughTen, 2..);
Write(oneThroughTen, 3..5);
Write(oneThroughTen, ^2..);
Write(oneThroughTen, ..^3);
Write(oneThroughTen, 3..^4);
Write(oneThroughTen, ^4..^2);
static void Write(int[] values, Range range) =>
Console.WriteLine($"{range}:\t{string.Join(", ", values[range])}");
// Sample output:
// 0..^0: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
// 0..3: 1, 2, 3
// 2..^0: 3, 4, 5, 6, 7, 8, 9, 10
// 3..5: 4, 5
// ^2..^0: 9, 10
// 0..^3: 1, 2, 3, 4, 5, 6, 7
// 3..^4: 4, 5, 6
// ^4..^2: 7, 8
Para obter mais informações, consulte Índices e intervalos.
O token .. também é usado para o elemento de propagação numa expressão de coleção.
Capacidade de sobrecarga do operador
Não podes sobrecarregar os .operadores, (), ^, e .. . O [] operador é também um operador não sobrecarregável. Use indexadores para dar suporte à indexação com tipos definidos pelo usuário.
Especificação da linguagem C#
Para obter mais informações, consulte as seguintes seções da especificação da linguagem C#:
- Acesso de membro
- Acesso a elementos
- Acesso de membro condicional nulo
- Expressões de invocação
Para obter mais informações sobre índices e intervalos, consulte a nota da proposta de funcionalidade.