Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
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 a membro): para aceder a um membro de um namespace ou de um tipo
[]
(elemento de matriz ou acesso de indexador): para acessar um elemento de matriz ou um indexador de tipo?.
e?[]
(operadores condicionais null): para executar uma operação de acesso a membro ou elemento apenas se o operando não for null- () (invocação): para chamar um método acedido ou invocar um delegado
^
(índice do fim): para indicar que a posição do elemento é a partir do fim de uma sequência..
(intervalo): para especificar um intervalo de índices que você pode usar para obter um intervalo de elementos de sequência
Expressão de acesso a membro .
Você usa o .
token para acessar um membro de um namespace ou um tipo, como demonstram os exemplos a seguir.
- Use
.
para aceder a um namespace aninhado dentro de outro namespace, como mostra o seguinte exemplo de uma diretivausing
using:
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
Você também pode usar .
para acessar um método de extensão.
Operador indexador []
Os colchetes, []
, são normalmente usados para acessar matrizes, indexadores ou elementos de 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 matriz estiver fora dos limites da dimensão correspondente de uma matriz, um IndexOutOfRangeException será lançado.
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 usuário da mesma forma que a indexação de matrizes. 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, colchetes podem ser usados para designar padrões de lista para uso em correspondência de padrões ou testes.
arr is ([1, 2, ..])
//Specifies that an array starts with (1, 2)
Operadores condicionais nulos ?.
e ?[]
Um operador condicional nulo aplica um acesso a membro (?.
) ou um acesso a elemento (?[]
) ao seu operando somente se esse operando for avaliado como não-nulo; caso contrário, ele retorna null
. Por outras palavras:
Se
a
avalia paranull
, o resultado dea?.x
oua?[x]
énull
.Se
a
é avaliado como não-nulo, o resultado dea?.x
oua?[x]
é o mesmo que o resultado dea.x
oua[x]
, respectivamente.Nota
Se
a.x
oua[x]
lança uma exceção,a?.x
oua?[x]
lançaria a mesma exceção para não nulo. Por exemplo, sea
for uma instância de array não nula ex
estiver fora dos limites dec2
,a?[x]
lançaria 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 T
de 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 false
numbers
é 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:
person?.FirstName = "Scott";
messages?[5] = "five";
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 -=
, são permitidas. 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 você gera um evento), como mostra o código abaixo:
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
Você também usa parênteses quando invoca um construtor com o operador new.
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 ^
Os operadores de índice e intervalo podem ser usados com um tipo que seja «contável». Um tipo enumerável é um tipo que tem uma propriedade chamada int
ou Count
com um acessador que pode ser acedido Length
. As expressões de coleção também dependem de tipos contáveis .
Nota
Matrizes unidimensionais são contáveis. Matrizes multidimensionais não o são. Os operadores ^
e ..
(intervalo) não podem ser usados em matrizes 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 do C# 13, o índice do operador final pode ser usado em um inicializador de objeto.
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 do início ou do final de uma sequência, como mostra o exemplo a seguir:
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..^0
a..
é equivalente aa..^0
a..
é 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
Os .
, ()
, ^
, e ..
operadores não podem ser sobrecarregados. O []
operador também é considerado 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.