Primeiras aulas do curso C# parte 7: Array e tipos genéricos

C# parte 7: Array e tipos genéricos

Conhecendo Array - Introdução

Seja bem vindo a mais um curso da nossa série de C#!

Começaremos aprendendo como funcionam os arrays no C#, como funciona a sintaxe de array e como podemos comportar vários itens do mesmo tipo e acessá-los e forma indexada (por exemplo, acessar o item na posição [0], na posição [1] ou na posição [2]).

Vamos aprender desde a sintaxe básica de array, como sintaxes mais complexas, por exemplo, a sintaxe de inicialização de array, na qual já conhecemos os items que fazem parte desse array e o número de itens que iremos utilizar nele.

Mais adiante, perceberemos que o array ainda é um pouco limitado para todas as situações que queremos resolver. Por isso, iremos abstrair as preocupações com índice, tamanho de array, entre outras, em uma lista.

Iremos criar uma ListaDeContaCorrente que irá abstrair essa complexidade do array. Nessa lista, vamos passar por vários métodos que nos ajudarão a treinar nossa lógica e o funcionamento dos arrays.

Vamos criar:

Ainda na lista, também iremos aprender vários recursos da linguagem C#, como os indexadores (o que são, como eles funcionam e como é a sintaxe deles, que é diferente da linguagem).

Também veremos aspectos relacionados aos argumentos dos nossos métodos, por exemplo, o que é um argumento params e quais são os benefícios de criarmos um método com esse tipo de argumento.

Vamos entender o que são implementações com argumentos de valores opcionais e qual é o mecanismo de funcionamento deles. Por exemplo, no construtor ListaDeContaCorrente, colocaremos um argumento CapacidadeInicial com um valor opcional (que, se não for atribuído por alguém, será 5), da seguinte forma:

public ListaDeContaCorrente(int capacidadeInicial = 5)
{
    _itens = new ContaCorrente[int CapacidadeInicial];
    _proximaPosiçao = 0;
} 

Além dessa sintaxe de argumento inicial, aprenderemos o que são e como funcionam os argumentos nomeados. É possível nomear um argumento no momento em que fazemos a chamada de um método, e tornar bastante explícito para a linguagem, no nosso código, que estamos atribuindo um valor em um argumento.

No nosso projeto, estamos criando uma ListaDeContaCorrente, uma lista de números inteiros, uma lista de clientes, entre outras. Para termos uma lista que comporta qualquer tipo de atribuição, vamos criar uma ListaDeObject.

Porém, talvez não seja interessante trabalharmos com object, pois perderemos os benefícios do compilador, que avisaria se tentássemos tentar chamar um método adicionar com uma referência de cliente, quando ele espera uma referênica de conta-corrente.

Portanto, iremos aprender como funcionam os tipos genéricos, entender como eles funcionam no nosso código, e também as consequências de usarmos um tipo genérico.

No nosso código, estamos usando o T várias vezes, como se fosse um tipo. Observe o exemplo:

public void AdicionarVarios(params T[] itens)
{ 
    foreach (T item in itens)
    { 
        Adicionar(item);
    } 
} 

Iremos entender o que é esse T dentro de uma classe genérica e como podemos utilizá-lo.

Até o próximo vídeo!

Conhecendo Array - Conhecendo array

No Visual Studio, temos aberta uma solução chamada ByteBank com dois projetos: ByteBank.Modelos e ByteBank.SistemaAgencia. Este último nada mais é do que o projeto que criamos nas últimas partes desse curso.

Agora vamos abrir o Program.cs:

{ 
    class Program
    { 
        static void Main(string[] args)
        { 
            Console.ReadLine();
        } 
    } 
} 

Para não precisar voltar nas outras partes do curso, você pode fazer o download do projeto nesse estado atual clicando aqui.

Durante o curso, fizemos a tarefa de criar variáveis diversas vezes. Para criar uma idade, por exemplo, usamos o tipo inteiro (int), o nome (idade) e ;Isso já é uma declaração de variável, mas podemos aproveitar para atribuir um valor, por exemplo, int idade = 15.

Vamos supor que, ao invés de uma só idade, desejamos trabalhar com várias idades para, posteriormente, fazer alguma operação (por exemplo, tirar uma média). Com tudo que vimos até agora, como criaremos mais idades no nosso programa?

Precisaremos criar mais uma variável, por exemplo, int idade = 28. Para não repetirmos o nome idade, vamos usar idade_2 (utilizando o underscore para ficar mais legível). Podemos repetir essa tarefa várias vezes:

int idade = 15;
int idade_2 = 28;
int idade_3 = 35;
int idade_4 = 50

Agora, como faríamos para realizar uma operação sobre esse código, por exemplo, tirar a média? Seríamos obrigados a somar cada variável e depois dividi-las por 4, certo? Usando WriteLine() para escrever na tela, teríamos algo como:

int media = (idade + idade_2 + idade_3 + idade 4) / 4;

Console.WriteLine(media)

Como podemos perceber, não ficou muito bom - inclusive, os nomes das variáveis ficaram estranhos, pois todos têm um índice (2, 3, 4...) exceto o primeiro. Por isso, vamos adicionar o índice _1 ao primeiro (sem se esquecer de alterar esse índice também na linha int media).

Se adicionarmos mais uma idade, por exemplo int idade_5 = 28;, também precisaremos adicioná-la na média, além de alterar a divisão para 5.

Não é interessante trabalhar dessa forma, pois precisaríamos nos preocupar com a convenção de nomes, poderíamos acabar errando um deles, e, quando fizéssemos uma operação com todos esses valores, seria necessário escrever todos eles manualmente.

Talvez seja melhor, ao invés de tirarmos a média dessa forma (somando os valores manualmente, um por um), criarmos um laço de repetição, por exemplo:

for(int indice = 1; indice <= 5; indice++)
{ 
    media += idade[indice];
} 

Ou seja, enquanto indice for menor ou igual a 5 (pois estamos trabalhando com 5 idades), vamos incrementar o valor de índice (indice++). Conforme alteramos a variável de índice, queremos acessar a variável correspondente.

O Visual Studio nos mostrará que esse não é um código válido. Não podemos acessar uma variável tentando juntá-la como uma string ou da forma que fizemos, até completar o que seria o nome dessa variável. O compilador precisa conhecer essa variável, e a maneira como apontamos a posição dela não funciona.

Vamos apagar esse código e a média que fizemos. Ainda estamos interessados em uma maneira de manipular vários dados e valores que compartilham o mesmo significado e possuem o mesmo contexto - nesse caso, não somente porque todos os valores são do tipo int, mas porque são várias idades sendo representadas no nosso programa.

Vamos criar essa idade de um jeito diferente. Como sabemos que ela é um inteiro, começaremos com int idades;. Usaremos colchetes para especificar o índice que estamos atribuindo para idades(no plural), assim:

int idades;

idades[1] = 15;
idades[2] = 28;
idades[3] = 35;
idades[4] = 50;
idades[5] = 28;

Se queremos que o compilador interprete essas instruções e possa guardar valores em posições específicas, as quais estamos indexando da nossa variável, usaremos int para representar que queremos um número inteiro nessas posições, mas, para tornarmos possível o acesso por meio de índices, devemos colocar um par de colchetes ([]).

O código irá acusar somente um erro, na primeira atribuição, dizendo que não podemos usar a variável idades porque ela ainda não recebeu um valor. Portanto, agora precisaremos colocar um valor em idades. Como idades não é um número inteiro, mas um conjunto de números inteiros, não poderemos usar int[] idades = 10;, por exemplo.

Para atribuir um valor em idades, usaremos new int[];. Dentro dos colchetes, precisamos informar ao compilador que estamos criando uma variável que irá suportar diversos valores do tipo inteiro. Porém, o compilador precisa saber quantos valores iremos colocar no pedaço de memória que será criado por ele. Como temos 5 idades, esse valor será [5].

Agora temos um código que compila:

{ 
    class Program
    { 
        static void Main(string[] args)
        { 
            int[] idades = new int[];

            idades[1] = 15;
            idades[2] = 28;
            idades[3] = 35;
            idades[4] = 50;
            idades[5] = 28;

            Console.Readline();
        } 
    } 
} 

Nós temos um tipo parece um int, mas não é, pois colocamos os colchetes. O int[] que criamos recebe algo que parece uma chamada de um construtor, mas não é, pois é um código diferente. Quando criamos uma instância, chamamos o construtor usando parênteses e passando parâmetros. Nesse caso, quando usamos os colchetes, nós informamos quantas posições de inteiros queremos.

Esse código que acabamos de criar no C# é um array. Vamos escrever um comentário indicando que isso é um "ARRAY de inteiros com 5 posições".

Para termos certeza de que esse código está funcionando, vamos executá-lo clicando em "Iniciar".

O programa apontará, na linha 22, o erro "System.IndexOutOfRangeException:", com a mensagem "O índice estava fora dos limites da matriz". Mas por que não conseguimos atribuir o valor 28 na posição [5]?

Nos cursos anteriores, vimos strings, manipulações e como funcionam os índices de caracteres, e aprendemos que, no C#, toda string começa a partir do índice 0.

Por exemplo, se nós temos uma string palavra, o índice do p é 0, o índice do a (o segundo caractere) é 1, e assim até o último a, que está no índice 6:

// palavra
// 0123456

Essa característica se repete também nos arrays. Portanto, se nosso array tem 5 posições, teremos os índices 0, 1, 2, 3 e 4, e o índice 5 estará na posição 6, fora do limite do array que acabamos de criar, e não conseguiremos acessá-lo.

Para esse código funcionar, temos que começar a atribuir os índices pelo 0, da seguinte maneira:

idades[0] = 15;
idades[1] = 28;
idades[2] = 35;
idades[3] = 50;
idades[4] = 28;

Dessa vez, ao executarmos o código, o programa não mostrará nenhuma mensagem de erro. Agora, como vamos acessar e mostrar na tela um valor do array que criamos - por exemplo, na posição 4?

Se estamos atribuindo a posição 4 com o nome da variável de array, o índice entre colchetes, e depois o =28;, iremos acessá-la da mesma forma, usando Console.WriteLine(idades[4]);.

O valor que esperamos é o 28, e se clicarmos em "Iniciar", 28 realmente será impresso na tela.

A seguir, vamos continuar estudando o que podemos fazer com arrays no C#.

Conhecendo Array - Valores padrões em arrays

Conseguimos acessar nosso array na posição [4] e mostrar, na tela, o número 28.

Mas e se não quisermos acessar a posição [4] e mostrá-la na tela diretamente, mas sim, antes, guardá-la numa variável e fazer um tratamento ou qualquer outro tipo de manipulação?

Para isso, criaremos uma variável chamada idadeNoIndice4(cujo tipo deixaremos em aberto por enquanto), que vai receber o valor da posição [4] do nosso array, assim:

TIPO_DA_VARIAVEL idadeNoIndice4 = idades[4];

Como o tipo do nosso array é int e ele tem 5 posições, teremos 5 espaços na memória do computador com valores de int. Portanto, o tipo da variável é int:

int idadenoIndice4 = idades[4];

Feito isso, não teremos nenhum erro de compilação, afinal, estamos acessando o valor que está na posição [4] daquele array.

Se tentarmos acessar simplesmente idades (int idadeNoIndice4 = idades;), o compilador não irá permitir, pois os tipos não serão compatíveis - teremos uma variável do tipo int (um número inteiro), e estaremos tentando atribuir nela um array, o que não é possível.

Já se o tipo for um array de int, ou seja, int[], o compilador irá permitir. Como estamos tentando acessar um número inteiro, usaremos int idadenoIndice4 = idades[4];.

Para termos certeza de que o código funciona, vamos escrever na tela:

{ 
    // ARRAY de inteiros, com 5 posições!
    int[] idades = new int[5];

    idades[0] = 15;
    idades[1] = 28;
    idades[2] = 35;
    idades[3] = 50;
    idades[4] = 28;

    int idadeNoIndice4 = idades[4];

    Console.WriteLine(idadeNoIndice4);

    Console.Readline();
} 

Se executarmos, o programa irá imprimir 28 na tela, da mesma forma que no vídeo anterior.

Como int não é um tipo de referência, mas sim um tipo de valor, quando recebemos na idadeNoIndice4 um valor do nosso array, estamos acessando a posição 4, pegando o valor 28 e atribuindo (copiando) ele para nossa variável.

Mas o que acontece se comentarmos a linha que atribui um valor na posição [4] do nosso array (// idades[4] = 28;)?

Veremos que o compilador não apontará nenhum erro, pois ele não analisa se estamos respeitando os índices do array que acabamos de criar - ou seja, ele não verifica se colocamos um valor em todas as posições.

Dessa forma, se tentarmos acessar um valor na posição [4] com essa linha comentada, o programa irá imprimir 0 na tela. Isso porque 0 é o valor padrão do inteiro, assim como o valor padrão do booleano é o false.

Quando criamos um array mas não inicializamos as posições, o valor padrão vai ser guardado em cada uma delas. Conseguimos acessar a posição [4] porque ela faz parte do nosso array, mas teremos 0 porque não inicializamos ela.

E o que acontece se a variável idades estiver recebendo uma referência nula? Vamos testar:

int [] idades = null;
// new int[5];

Se idades estiver recebendo uma referência nula, não saberemos em que lugar da memória os valores de idades (15, 28, 35 e 50) serão guardados e, portanto, não existirá um lugar para acessar esses índices.

Para confirmar isso, executaremos a aplicação clicando em "Iniciar". O resultado é uma exceção "System.NullReferenceException".

Vamos parar a aplicação e, para que ela volte a executar normalmente, faremos a variável idades receber uma referência do nosso "novo array de inteiros" (new int[5]).

Diferente dos inteiros, o array não é um tipo de valor, mas sim um tipo de referência.

Vamos testar o que acontece quando criamos um novo array no nosso programa e tentamos acessar a posição [3]:

int[] outroArray = idades;

Console.WriteLine(outroArray[3]);

Quando executamos a aplicação, a tela retorna o valor 50. Mas como array é um tipo de referência, já esperávamos por isso, certo?

Nós criamos um objeto de array na memória do computador, conseguimos ter uma referência para esse objeto a partir da variável idades e, posteriormente, a partir de outra variável, chamada outroArray.

Também podemos criar outros tipos de array, por exemplo o tipo bool[], um array de booleanos. Primeiro precisaremos criar esse array na memória do computador. Para isso, usaremos new bool[]. Entre colchetes, colocaremos a quantidade de booleanos com que queremos trabalhar e criaremos os valores para as posições:

bool[] arrayDeBoleanos = new bool[10]; 

arrayDeBooleanos[0] = true;
arrayDeBooleanos[1] = false;
arrayDeBooleanos[2] = false;
// e assim sucessivamente em cada uma das posições 

Console.Readline();

A sintaxe de criação de um array é essa: o tipo que iremos armazenar em cada uma das posições seguido de colchetes ([]).

Mas e o nosso problema de tirar uma média ?

Nós criamos um array, conseguimos centralizar em um lugar todos os valores que fazem parte do contexto do nosso problema, e vimos como é feito o acesso por meio de índices.

Para simplificar a explicação, vamos retornar para o nosso primeiro array:

{ 
    // ARRAY de inteiros, com 5 posições!
    int[] idades = new int[5];

    idades[0] = 15;
    idades[1] = 28;
    idades[2] = 35;
    idades[3] = 50;
    idades[4] = 28;

    int idadeNoIndice4 = idades[4];

    Console.Readline();
} 

Os índices são, na verdade, uma expressão que retorna um número inteiro. O literal 0 e o literal 1, por exemplo, são expressões de números inteiros (0 e 1, respectivamente).

Portanto, em idades[4];, podemos colocar outra expressão, por exemplo idades[2 +2];. Como essa é uma expressão que vai retornar um inteiro, o compilador a aceita sem problemas. Quando executamos, o programa imprime 28 na tela.

Já se criarmos outra variável int indice = 4; e colocamos indice no lugar da posição (idades[indice]), teremos outra expressão que retorna um número inteiro. Se executarmos a aplicação, novamente teremos 28 na tela.

Agora ficou mais fácil enxergar como podemos resolver o problema de tirar a média das idades, certo? Podemos acessar índice a índice, somar todos esses valores em uma variável ou acumulador, e depois dividí-los. Vamos escrever esse código?

Sobre o curso C# parte 7: Array e tipos genéricos

O curso C# parte 7: Array e tipos genéricos possui 172 minutos de vídeos, em um total de 40 atividades. Gostou? Conheça nossos outros cursos de .NET em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda .NET acessando integralmente esse e outros cursos, comece hoje!

Plus

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$85
à vista R$1.020
Matricule-se

Pro

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$120
à vista R$1.440
Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas