Compartilhar via


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ção R e um tipo Tde elemento não matriz.
  • Um tipo de matriz do formulário T[R][R₁]...[Rₓ] é uma matriz com classificação R e um tipo T[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 de int. 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 de object[] para IList<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, pois oa1 as referências a um object[] e não a um string[]. No entanto, a conversão (IList<string>)oa2 não fará com que uma exceção seja lançada, pois oa2 as referências a um string[].

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).BA 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 que value seja uma null referência ou uma referência a um objeto de um tipo compatível com o tipo de elemento real de array. Em Main, as duas primeiras invocações de Fill succeed, mas a terceira invocação faz com que a System.ArrayTypeMismatchException seja lançada ao executar a primeira atribuição para array[i]. A exceção ocorre porque uma caixa não pode ser armazenada int em uma string 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 for z 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