O documento resume conceitos fundamentais de C#, incluindo: 1) tipos de valor e referência, pilha e heap; 2) boxing e unboxing; 3) coleções genéricas como List, Dictionary e suas complexidades; 4) IDisposable e uso de recursos; 5) diferença entre throw e throw ex.
4. Value Type
• Quando uma instância value type é criada, um único espaço
na memória é alocado para armazenar o valor.
Tipos primitivos como int, float, bool, char e structs são value
type. Em tempo de execução quando trabalhamos com value
type, estamos lidando diretamente com os dados e isso pode
ser muito eficiente.
4
5. Reference Type
• Quando uma instância reference type é criada, um espaço na
memória é alocada com o endereço da memoria(ponteiro)
onde os dados estão.
Classes, qualquer Array mesmo que seus membros sejam value
type, string e delegates são reference type.
5
8. Stack e Heap
• A memória da aplicação é a porção da memória do
computador alocado pelo sistema operacional para rodar a
aplicação. Esta memória pode ser alocada em duas partes
stack e heap.
• A categoria do tipo de dados determina como ele será
alocado na memória.
8
9. Stack e Heap
• O que vai para a Stack e Heap?
Type
Onde
Value Type
Sempre vão para onde eles
foram declarados.
Reference Type
Sempre vai para a Heap
9
10. Stack
• A CPU organiza a memória da Stack de forma muito eficiente, leitura e
escrita para empilhar/desempilhar variáveis são extremamente rápidas.
• Variaveis são alocadas e liberadas automaticamente.
• Stack é uma estrutura de dados “FILO” (First in, last out).
• Cada vez que uma função declara uma nova variável, ela é empilhada na
Stack. Cada vez que uma função termina, todas as variáveis empilhadas
na Stack por esta função, são liberadas.
Memória da aplicação
Stack
Heap
Idade: 0
10
11. Heap
• A Heap é uma região de memória do seu computador que
não é gerenciado “automaticamente” para você, a heap tem
que se preocupar com coleta de lixo ae que entra o famoso
GC - Garbage collector que é responsável por manter a Heap
limpa.
Memória da aplicação
Stack
Heap
person: null
11
12. Heap
• Se tentarmos acessar person.Idade vai ocorrer a Exception
System.NullReferenceException: Object reference not set to
an instance of an object.
Memória da aplicação
Stack
Heap
person: null
12
13. Heap
• Após criamos uma instância do objeto a nossa memória
ficara assim:
Memória da aplicação
Stack
Heap
person: 123
123: Idade | 25
13
15. Box/Unboxing
• Boxing é o processo de conversão de um value type para o
tipo object.
• No exemplo a seguir, a variável de inteiro i é boxed e
atribuído ao objeto o.
• O objeto o pode então ser unboxed e atribuída a variável
inteiro i:
15
16. Box/Unboxing
• É melhor evitar o seu uso em situações com um alto número
de box/unboxing, por exemplo, em classes de coleções não
genéricas.
• Você pode evitar boxing usando coleções genéricas, como
System.Collections.Generic.List<T>.
• O processo de Boxing pode levar até 20 vezes mais do que
uma atribuição de referência simples.
16
18. Collections
• O namespace System.Collections.Generic deve atender a
99% das suas necessidades.
• Coleções Associativas
Coleções associativas armazenam um valor na
coleção, fornecendo uma chave que é usado para adicionar /
remover / procurar o item. Assim, a coleção associa o valor com
a chave. Essas coleções são mais úteis quando você precisa
pesquisar / manipular uma coleção usando um valor de chave.
Por exemplo, se você quiser procurar um pedido em uma
coleção de pedidos por um ID de pedido, você pode ter uma
coleção associativo onde a chave é o id do pedido e o valor é o
pedido.
18
19. Collections
• O Dictionary<TKey,TValue> é provavelmente a classe de
coleções associativas mais utilizada. O
Dictionary<TKey,TValue> é a classe mais rápida para
pesquisas / inserções / exclusões, porque ele usa uma tabela
hash debaixo das cobertas. Como as chaves são hash, o tipo
da chave deve implementar corretamente GetHashCode () e
Equals () ou você deve fornecer um IEqualityComparer
externo na construção do dicionário.
• Complexidade constante O(1) , o que significa que não
importa quão grande o dicionário fica, o tempo que leva para
encontrar algo permanece relativamente constante. Isto é
altamente desejável para pesquisas de alta velocidade.
19
20. Collections
• O SortedDictionary<TKey,TValue> é semelhante ao
Dictionary mas muito diferente na execução. Usa uma árvore
binária debaixo das cobertas para manter os itens em ordem
pela chave, o tipo da chave deve implementar corretamente
IComparable para que as chaves possam ser classificadas.
• Usar quando precisar ter pesquisa rápidas e manter o
Dictionary em ordem pela chave.
• Complexidade O (log n) para
inserção/remoção/pesquisa, com o tempo logarítmica, você
pode dobrar o tamanho da coleção e só tera de realizar uma
comparação extra para encontrar o item.
20
21. Collections
• O SortedList<TKey,TValue> como o SortedDictionary usa a
chave para ordena seus itens. No entanto, os itens em um
SortedList são armazenados como um array.
• Usa menos memoria que o SortedDictionary
• Inserções e deleções são lineares O (n), porque apagar ou
adicionar um item pode implicar a transferência de todos os
itens para cima ou para baixo na lista. Pesquisas são O(log n).
• Usar quando quiser manter os itens em ordem e tiver poucas
inserções/remoção.
• Indexação de matriz é mais rápido do que seguir os links dos
objetos, ou seja, as pesquisas são mais rápidas que um
SortedDictionary.
21
22. Collections
• Coleções não associativas
Não usam uma chave para manipular a coleção, usam outros
meios para manipular a coleção, como o indice.
• List<T> é uma série de itens que crescem uma vez que sua
capacidade é ultrapassada. Porque os itens são armazenados
de forma continua ,como uma matriz, você pode acessar os
itens na lista por índice muito rapidamente. No entanto
inserção e remoção no início ou no meio da lista são muito
caros porque você deve mudar todos os itens para cima ou
para baixo.
• Adição e remoção no fim de uma lista é uma operação
constante O(1) e para os outros casos O(n).
22
23. Collections
• LinkedList<T> é uma implementação básica de uma lista
duplamente ligada. Isso significa que você pode adicionar ou
remover itens no meio de uma lista ligada muito
rapidamente (porque não há itens para mover para cima ou
para baixo na memória), mas você também perde a
capacidade de buscar os itens pelo índice de posição
rapidamente. Na maioria das vezes, tendemos a favorecer
List <T> sobre LinkedList <T> a menos que você esteja
fazendo um monte de adição e remoção na coleção, caso em
que a LinkedList <T> pode fazer mais sentido.
23
24. Collections
• HashSet<T> fornece operações de conjunto de alto
desempenho. Um conjunto é uma coleção que não contém
elementos duplicados, e cujos elementos estão em nenhuma
ordem particular.
• Parece com o Dictionary<TKey,TValue>.
• HashSet <T> é útil para pesquisas super rápidas onde a
ordem não é importante. Mais uma vez, como no
dicionário, o tipo deve ter uma implementação válida de
GetHashCode () e Equals (), ou você deve fornecer um
IEqualityComparer adequada ao HashSet <T> em
construção.
24
25. Collections
• Stack<T> e Queue<T>, o Stack<T> é um LIFO(last-in-firstout) onde os itens são adicionados e removidos do topo da
pilha. O Queue<T> é um FIFO(first-in-first-out) onde os itens
são adicionados no final da fila e remove os itens do começo.
• Exemplo do uso da Stack seria empilhar as ações e, em
seguida, ser capaz de desfazer as ações em ordem
inversa, conforme necessário.
• Exemplo do uso da Queue: Você precisa processar os itens na
ordem em que eles vieram, como um gerenciador de
impressão ou filas de espera. onde você precisa para
processar os itens na ordem em que eles vieram, como o
gerenciador de impressão ou filas de espera
25
26. Collections
• Essas coleções são otimizados para uso em situações em que
multi-threaded é desejado:
• ConcurrentQueue
• ConcurrentStack
• ConcurrentDictionary
• ConcurrentBag (Suporta dados duplicados)
26
28. IDisposable
• O Garbage Collector (Coletor de Lixo) automaticamente
libera a memória alocada para um objeto gerenciado quando
este objeto não está mais em uso. No entanto, não há como
prever quando o Garbage Collector irá realizar a coleta do
lixo. Além disso, o garbage collector não tem conhecimento
dos recursos não gerenciados.
• Usamos o método Dispose desta interface para liberar
explicitamente recursos não gerenciados.
28
29. IDisposable
• Ao chamar uma classe que implementa a
interface IDisposable, podemos usar o try/finally para
certificar-se que os recursos são descartados mesmo se uma
exceção interromper sua aplicação.
• Observe que você pode usar a instrução using em vez
do try/finally.
• Ambas as abordagens são essencialmente a mesma coisa, a
única diferença é que, na primeira abordagem, temos de
liberar o recurso explicitamente, e na segunda abordagem a
liberação de recursos é feita automaticamente. using é a
maneira recomendada porque evita que os programadores
esqueçam de fazer.
29
32. throw vs throw ex
• throw só pode ser usado dentro do escopo de um bloco
catch, porque precisa garantir que existe uma exceção.
• throw {Exception} permite que você forneça uma nova
exceção e pode ser usada em qualquer lugar.
• Somente throw pode ser usado para relançar a exceção atual
dentro de um catch vazio.
• Ambos relançam o objeto de exceção atual, mas “throw e”
redefine alguns parâmetros como o StackTrace.
32