Olá Pessoal, Vou fazer uma série sobre (C Sharp) C# para iniciantes.
Atendendo à diversos pedidos vou procurar abordar de uma forma diferente a transferência de conhecimentos nessa linguagem, apostila e tutorial tem de monte na internet, a intenção não é essa, vamos abordar necessidades reais de quem quer dar os primeiros passos em C# e agora quer aprender mais.
Só para começar, um pouquinho de história:
O C# é uma linguagem derivada do C++, mas também tem base em Java e Object Pascal.
Criada em meados de 1999 por Anders Hejlsberg (pai do Turbo Pascal e Delphi) vem desde 2001 ganhando espaço e se tornou uma das linguagens mais populares da atualidade.
Vamos dar o primeiro passo:
Variáveis
Toda variável é uma alocação de uma quantidade de memória, é nesse espaço de memória que está armazenado o conteúdo da variável, internamente uma variável possui um ponteiro, o ponteiro para o sistema operacional é um endereçamento físico de memória, serve para localizar onde está armazenado tal dado.
A declaração de variável em C#:
int MeuInteiro;
Deve-se sempre inicializar uma variável:
int MeuInteiro = 0;
Stack e Heap
O gerenciamento da memória no C# é feito em duas áreas de memória, o Stack e o Heap.
O Stack é uma área bem pequena de memória (alguns KB) e funciona no formato de pilha.
“Pilha é uma estrutura de dados em que a inserção e a remoção de elementos de uma sequência se faz pela mesma extremidade, geralmente designada por topo da pilha”
Ou seja, o último que entra na pilha é o primeiro que sai (LIFO – Last-In-First-Out)
Qualquer dado inserido na Stack é automaticamente retirado automaticamente após a conclusão do processo que a alocou, isso livra o programador de se preocupar com isso.
Quando a Stack atinge seu tamanho máximo temos um problema muito conhecido como “stack overflow”. Os dados armazenados na Stack são chamados de “Value Types”.
A Heap é uma área de memória bem grande, diferente da Stack que é pequena, seu tamanho muda dinamicamente conforme o uso, a Heap é acessada indiretamente, por meio de referência, por isso chamamos os dados da Heap de “Reference Type”.
Existe um processo chamado Garbage Collector (GC) que é responsável pela limpeza desta área de memória.
O custo de se criar um objeto na Heap é muito maior do que na Stack, sendo assim na área de memória Stack nós temos os Value Types a seguir:
Tipos numéricos (int, long, short etc), ponto flutuante (float, double), decimal, booleanos (true e false) e estruturas definidas pelo usuário (struct).
Na Heap nós temos os Reference Types do tipo: Classes, Interfaces e Delegates.
As características dos tipos alocados em cada uma dessas áreas são as seguintes:
Value Types:
- Uma variável deste tipo contém o valor, e não um endereço de referência para o valor;
- Derivam de System.ValueTypes;
- Variáveis de escopo local precisam ser inicializadas antes de serem utilizadas;
- Atribuir o valor de variável a outra, implicitamente, é feita uma cópia do conteúdo da variável. Sendo assim, qualquer alteração no conteúdo de uma delas, não afetará a outra. Quanto maior for um objeto deste tipo mais custosa será sua cópia.
Reference Types:
- Uma variável contém a referência (ou endereço) para o objeto que está na Heap;
- Atribuir o valor de uma variável para outra faz uma cópia da referência, e não do próprio objeto. Ou seja, não é feita a cópia do objeto, e sim do endereço de memória do objeto, o que não gera muito custo para objetos grandes;
- São alocados na Heap e seus objetos são coletados pelo Garbage Collector;
- São passados por referência, enquanto que Value Types são passados por valor. Ou seja, a alteração de um objeto afetará todas as instâncias que apontam para ele.
Boxing e Unboxing
Boxing é o processo de converter um “Value Type” para o tipo de object ou a qualquer tipo de interface implementada por este tipo de valor “Reference Type”.
Unboxing extrai o “Value Type” do objeto. Transforma um objeto em um tipo simples.
// Vamos fazer um Boxing
int i = 123;
object obj = i;
// Agora vamos fazer Unboxing
obj = 123;
i = (int)obj;
Simples né?
O Garbage Collector (GC)
Como na Heap todos objetos são referenciados, o GC verifica se existe alguma variável fazendo referência a determinado objeto, caso não encontre ele desaloca “Coleta” aquela área de memória.
Um fato interessante, por mais que se chame o Garbage Collector a sensação que temos é de que ele irá entrar em ação no mesmo instante, mas não, estamos apenas sinalizando a ele. “Passe por aqui GC”.
Não é recomendado chamar manualmente o GC, deixe com que ele trabalhe de sua forma.
Abaixo estamos chamando o GC, porém sinalizando para que ele aguarde o trabalho em memória terminar:
GC.Collect();
GC.WaitForPendingFinalizers();
Passagem de Valor ou por Referência
Dada as funções:
public void FuncaoPorValor(int numero)
{
numero = 10;
}
public void FuncaoPorReferencia(ref int numero)
{
numero = 10;
}
A única diferença entre as duas é que uma trata a variável “numero” passada por valor e a outra trata a variável “numero” por referência.
Observemos os resultados:
int variavel = 0;
FuncaoPorValor(variavel);
MessageBox.Show("Resultado = " + variavel.ToString());
// Resultado = 0 Foi passada uma cópia da variável pro método.
int variavel2 = 0;
FuncaoPorReferencia(variavel2);
MessageBox.Show("Resultado = " + variavel2.ToString());
// Resultado = 10 Foi passada a referência da variável pro método.
Normalmente quando passamos uma variável para uma função, estamos passando uma cópia dela para a função trabalhar.
Caso essa cópia seja modificada a original permanece igual.
Quando passamos a variável por referência, um ponteiro de memória está sendo passado, ou seja, caso seja modificada a própria variável está sendo alterada, pois o ponteiro de memória aponta para a alocação original.
E por hoje ficamos por aqui.
Espero que aproveitem e em caso de dúvidas podem postá-las nos comentários.
Referências:
- http://pt.wikipedia.org/wiki/C#
- http://www.linhadecodigo.com.br/artigo/1246/struct-e-class-quando-usar.aspx