17 matrizes
17.1 Geral
Uma matriz é uma estrutura de dados que contém algumas variáveis acessadas por meio de índices calculados. As variáveis contidas em uma matriz, também chamadas de elementos da matriz, são todas do mesmo tipo, e esse tipo é chamado de tipo de elemento da matriz.
Uma matriz tem uma classificação que determina o número de índices associados a cada elemento da matriz. A classificação de uma matriz também é chamada de dimensões da matriz. Uma matriz com uma classificação de um é chamada de matriz unidimensional. Uma matriz com uma classificação maior que um é chamada de matriz multidimensional. Matrizes multidimensionais de tamanhos específicos são frequentemente chamadas de matrizes bidimensionais, matrizes tridimensionais e assim por diante. Cada dimensão de uma matriz tem um comprimento associado que é um número integral maior ou igual a zero. Os comprimentos de dimensão não fazem parte do tipo da matriz, mas são estabelecidos quando uma instância do tipo de matriz é criada em tempo de execução. O comprimento de uma dimensão determina o intervalo válido de índices para essa dimensão: Para uma dimensão de comprimento N
, os índices podem variar de 0
a N – 1
inclusivo. O número total de elementos em uma matriz é o produto dos comprimentos de cada dimensão na matriz. Se uma ou mais das dimensões de uma matriz tiverem um comprimento de zero, a matriz será considerada vazia.
O tipo de elemento de uma matriz pode ser um tipo de matriz (§17.2.1). Essas matrizes de matrizes são distintas das matrizes multidimensionais e podem ser usadas para representar "matrizes irregulares".
Exemplo:
int[][] pascals = { new int[] {1}, new int[] {1, 1}, new int[] {1, 2, 1}, new int[] {1, 3, 3, 1} };
exemplo de fim
Cada tipo de matriz é um tipo de referência (§8.2). O tipo de elemento de uma matriz pode ser qualquer tipo, incluindo tipos de valor e tipos de matriz.
17.2 Tipos de matriz
17.2.1 Geral
As produções gramaticais para tipos de matriz são fornecidas em §8.2.1.
Um tipo de matriz é escrito como um non_array_type seguido por um ou mais rank_specifiers.
Um non_array_type é qualquer tipo que não seja em si um array_type.
A classificação de um tipo de matriz é dada pela rank_specifier mais à esquerda no array_type: Um rank_specifier indica que a matriz é uma matriz com uma classificação de um mais o número de tokens ",
" no rank_specifier.
O tipo de elemento de um tipo de matriz é o tipo que resulta da exclusão do rank_specifier mais à esquerda:
- Um tipo de matriz do formulário
T[R]
é uma matriz com classificaçãoR
e um tipoT
de elemento não matriz. - Um tipo de matriz do formulário
T[R][R₁]...[Rₓ]
é uma matriz com classificaçãoR
e um tipoT[R₁]...[Rₓ]
de elemento .
Na verdade, os rank_specifiers são lidos da esquerda para a direita antes do tipo de elemento final que não é da matriz.
Exemplo: O tipo in
T[][,,][,]
é uma matriz unidimensional de matrizes tridimensionais de matrizes bidimensionais deint
. exemplo de fim
Em tempo de execução, um valor de um tipo de matriz pode ser null
ou uma referência a uma instância desse tipo de matriz.
Observação: Seguindo as regras da seção 17.6, o valor também pode ser uma referência a um tipo de matriz covariante. nota final
17.2.2 O tipo System.Array
O tipo System.Array
é o tipo base abstrato de todos os tipos de matriz. Existe uma conversão de referência implícita (§10.2.8) de qualquer tipo de matriz para System.Array
e para qualquer tipo de interface implementado pelo System.Array
. Existe uma conversão de referência explícita (§10.3.5) de e qualquer tipo de interface implementado por System.Array
para qualquer tipo de System.Array
matriz. System.Array
não é em si um array_type. Em vez disso, é um class_type do qual todos os array_types são derivados.
Em tempo de execução, um valor do tipo System.Array
pode ser null
ou uma referência a uma instância de qualquer tipo de matriz.
17.2.3 Arrays e interfaces de coleção genérica
Uma matriz T[]
unidimensional implementa a interface System.Collections.Generic.IList<T>
(IList<T>
abreviadamente) e suas interfaces básicas. Assim, há uma conversão implícita de T[]
para IList<T>
e suas interfaces base. Além disso, se houver uma conversão de referência implícita de S
toT
, implementa IList<T>
S[]
e há uma conversão de referência implícita de S[]
to IList<T>
e suas interfaces base (§10.2.8). Se houver uma conversão de referência explícita de S
para T
, haverá uma conversão de referência explícita de S[]
para IList<T>
e suas interfaces base (§10.3.5).
Da mesma forma, uma matriz T[]
unidimensional também implementa a interface System.Collections.Generic.IReadOnlyList<T>
(IReadOnlyList<T>
abreviadamente) e suas interfaces básicas. Assim, há uma conversão implícita de T[]
para IReadOnlyList<T>
e suas interfaces base. Além disso, se houver uma conversão de referência implícita de S
toT
, implementa IReadOnlyList<T>
S[]
e há uma conversão de referência implícita de S[]
to IReadOnlyList<T>
e suas interfaces base (§10.2.8). Se houver uma conversão de referência explícita de S
para T
, haverá uma conversão de referência explícita de S[]
para IReadOnlyList<T>
e suas interfaces base (§10.3.5).
Exemplo: Por exemplo:
class Test { static void Main() { string[] sa = new string[5]; object[] oa1 = new object[5]; object[] oa2 = sa; IList<string> lst1 = sa; // Ok IList<string> lst2 = oa1; // Error, cast needed IList<object> lst3 = sa; // Ok IList<object> lst4 = oa1; // Ok IList<string> lst5 = (IList<string>)oa1; // Exception IList<string> lst6 = (IList<string>)oa2; // Ok IReadOnlyList<string> lst7 = sa; // Ok IReadOnlyList<string> lst8 = oa1; // Error, cast needed IReadOnlyList<object> lst9 = sa; // Ok IReadOnlyList<object> lst10 = oa1; // Ok IReadOnlyList<string> lst11 = (IReadOnlyList<string>)oa1; // Exception IReadOnlyList<string> lst12 = (IReadOnlyList<string>)oa2; // Ok } }
A atribuição
lst2 = oa1
gera um erro em tempo de compilação, pois a conversão deobject[]
paraIList<string>
é uma conversão explícita, não implícita. A conversão(IList<string>)oa1
fará com que uma exceção seja lançada em tempo de execução, poisoa1
as referências a umobject[]
e não a umstring[]
. No entanto, a conversão (IList<string>)oa2
não fará com que uma exceção seja lançada, poisoa2
as referências a umstring[]
.exemplo de fim
Sempre que houver uma conversão de referência implícita ou explícita de S[]
para IList<T>
, há também uma conversão de referência explícita de IList<T>
e suas interfaces base para S[]
(§10.3.5).
Quando um tipo S[]
de matriz implementa IList<T>
, alguns dos membros da interface implementada podem lançar exceções. O comportamento preciso da implementação da interface está além do escopo desta especificação.
17.3 Criação de array
As instâncias de matriz são criadas por array_creation_expressions (§12.8.16.5) ou por declarações de campo ou variável local que incluem um array_initializer (§17.7). As instâncias de matriz também podem ser criadas implicitamente como parte da avaliação de uma lista de argumentos envolvendo uma matriz de parâmetros (§15.6.2.4).
Quando uma instância de matriz é criada, a classificação e o comprimento de cada dimensão são estabelecidos e permanecem constantes durante todo o tempo de vida da instância. Em outras palavras, não é possível alterar a classificação de uma instância de matriz existente, nem é possível redimensionar suas dimensões.
Uma instância de matriz é sempre de um tipo de matriz. O System.Array
tipo é um tipo abstrato que não pode ser instanciado.
Os elementos de matrizes criados por array_creation_expressions são sempre inicializados com seu valor padrão (§9.3).
17.4 Acesso ao elemento da matriz
Os elementos de matriz são acessados usando element_access expressões (§12.8.11.2) do formulário A[I₁, I₂, ..., Iₓ]
, onde A
é uma expressão de um tipo de matriz e cada Iₑ
uma é uma expressão do tipo int
, uint
, long
, ulong
, ou pode ser convertida implicitamente em um ou mais desses tipos. O resultado de um acesso a um elemento de array é uma variável, ou seja, o elemento de array selecionado pelos índices.
Os elementos de uma matriz podem ser enumerados usando uma foreach
instrução (§13.9.5).
17.5 Membros da matriz
Cada tipo de matriz herda os membros declarados System.Array
pelo tipo.
17.6 Covariância de matriz
Para quaisquer dois reference_type s e , se existir uma conversão de referência implícita (§10.2.8) ou conversão de referência explícita (§10.3.5) de A
para B
, então a mesma conversão de referência também existe do tipo A[R]
de matriz para o tipo B[R]
de matriz , onde R
é qualquer rank_specifier (mas o mesmo para ambos os tipos de matriz).B
A
Essa relação é conhecida como covariância de matriz. A covariância de matriz, em particular, significa que um valor de um tipo A[R]
de matriz pode realmente ser uma referência a uma instância de um tipo B[R]
de matriz , desde que exista uma conversão de referência implícita de B
para A
.
Devido à covariância de matriz, as atribuições a elementos de matrizes de tipo de referência incluem uma verificação de tempo de execução que garante que o valor que está sendo atribuído ao elemento de matriz seja realmente de um tipo permitido (§12.21.2).
Exemplo:
class Test { static void Fill(object[] array, int index, int count, object value) { for (int i = index; i < index + count; i++) { array[i] = value; } } static void Main() { string[] strings = new string[100]; Fill(strings, 0, 100, "Undefined"); Fill(strings, 0, 10, null); Fill(strings, 90, 10, 0); } }
A atribuição de no
array[i]
Fill
método inclui implicitamente uma verificação de tempo de execução, que garante quevalue
seja umanull
referência ou uma referência a um objeto de um tipo compatível com o tipo de elemento real dearray
. EmMain
, as duas primeiras invocações deFill
succeed, mas a terceira invocação faz com que aSystem.ArrayTypeMismatchException
seja lançada ao executar a primeira atribuição paraarray[i]
. A exceção ocorre porque uma caixa não pode ser armazenadaint
em umastring
matriz.exemplo de fim
A covariância de matriz especificamente não se estende a matrizes de value_types. Por exemplo, não existe nenhuma conversão que permita que um int[]
seja tratado como um object[]
.
17.7 Inicializadores de matriz
Os inicializadores de matriz podem ser especificados em declarações de campo (§15.5), declarações de variáveis locais (§13.6.2) e expressões de criação de matriz (§12.8.16.5):
array_initializer
: '{' variable_initializer_list? '}'
| '{' variable_initializer_list ',' '}'
;
variable_initializer_list
: variable_initializer (',' variable_initializer)*
;
variable_initializer
: expression
| array_initializer
;
Um inicializador de array consiste em uma sequência de inicializadores variáveis, delimitados por tokens "{
" e "}
" e separados por tokens ",
". Cada inicializador de variável é uma expressão ou, no caso de uma matriz multidimensional, um inicializador de matriz aninhada.
O contexto no qual um inicializador de matriz é usado determina o tipo de matriz que está sendo inicializada. Em uma expressão de criação de matriz, o tipo de matriz precede imediatamente o inicializador ou é inferido das expressões no inicializador de matriz. Em uma declaração de campo ou variável, o tipo de matriz é o tipo do campo ou variável que está sendo declarado. Quando um inicializador de matriz é usado em uma declaração de campo ou variável,
int[] a = {0, 2, 4, 6, 8};
é simplesmente uma abreviação para uma expressão de criação de matriz equivalente:
int[] a = new int[] {0, 2, 4, 6, 8};
Para uma matriz unidimensional, o inicializador de matriz deve consistir em uma sequência de expressões, cada uma com uma conversão implícita para o tipo de elemento da matriz (§10.2). As expressões inicializam elementos de matriz em ordem crescente, começando com o elemento no índice zero. O número de expressões no inicializador de matriz determina o comprimento da instância de matriz que está sendo criada.
Exemplo: o inicializador de matriz acima cria uma
int[]
instância de comprimento 5 e, em seguida, inicializa a instância com os seguintes valores:a[0] = 0; a[1] = 2; a[2] = 4; a[3] = 6; a[4] = 8;
exemplo de fim
Para uma matriz multidimensional, o inicializador de matriz deve ter tantos níveis de aninhamento quanto dimensões na matriz. O nível de aninhamento mais externo corresponde à dimensão mais à esquerda e o nível de aninhamento mais interno corresponde à dimensão mais à direita. O comprimento de cada dimensão da matriz é determinado pelo número de elementos no nível de aninhamento correspondente no inicializador da matriz. Para cada inicializador de matriz aninhada, o número de elementos deve ser o mesmo que os outros inicializadores de matriz no mesmo nível.
Exemplo: O exemplo:
int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
Cria uma matriz bidimensional com um comprimento de cinco para a dimensão mais à esquerda e um comprimento de dois para a dimensão mais à direita:
int[,] b = new int[5, 2];
e, em seguida, inicializa a instância da matriz com os seguintes valores:
b[0, 0] = 0; b[0, 1] = 1; b[1, 0] = 2; b[1, 1] = 3; b[2, 0] = 4; b[2, 1] = 5; b[3, 0] = 6; b[3, 1] = 7; b[4, 0] = 8; b[4, 1] = 9;
exemplo de fim
Se uma dimensão diferente da mais à direita for fornecida com comprimento zero, as dimensões subsequentes também terão comprimento zero.
Exemplo:
int[,] c = {};
Cria uma matriz bidimensional com um comprimento de zero para a dimensão mais à esquerda e mais à direita:
int[,] c = new int[0, 0];
exemplo de fim
Quando uma expressão de criação de matriz inclui comprimentos de dimensão explícitos e um inicializador de matriz, os comprimentos devem ser expressões constantes e o número de elementos em cada nível de aninhamento deve corresponder ao comprimento de dimensão correspondente.
Exemplo: Aqui estão alguns exemplos:
int i = 3; int[] x = new int[3] {0, 1, 2}; // OK int[] y = new int[i] {0, 1, 2}; // Error, i not a constant int[] z = new int[3] {0, 1, 2, 3}; // Error, length/initializer mismatch
Aqui, o inicializador for
y
resulta em um erro de tempo de compilação porque a expressão de comprimento de dimensão não é uma constante, e o inicializador forz
resulta em um erro de tempo de compilação porque o comprimento e o número de elementos no inicializador não concordam.exemplo de fim
Observação: C# permite uma vírgula à direita no final de uma array_initializer. Essa sintaxe fornece flexibilidade na adição ou exclusão de membros de tal lista e simplifica a geração de máquina dessas listas. nota final
ECMA C# draft specification