You are on page 1of 207

Conhea mais da Caelum.

Cursos Online
www.caelum.com.br/online
Blog Caelum
blog.caelum.com.br
Newsletter
www.caelum.com.br/newsletter
Facebook
www.facebook.com/caelumbr
Twitter
twitter.com/caelum
Casa do Cdigo
Livros para o programador
www.casadocodigo.com.br
Sobre esta apostila
Esta apostila da Caelumvisa ensinar de uma maneira elegante, mostrando apenas o que necessrio e quando
necessrio, no momento certo, poupando o leitor de assuntos que no costumam ser de seu interesse em
determinadas fases do aprendizado.
A Caelum espera que voc aproveite esse material. Todos os comentrios, crticas e sugestes sero muito
bem-vindos.
Essa apostila constantemente atualizada e disponibilizada no site da Caelum. Sempre consulte o site para
novas verses e, ao invs de anexar o PDF para enviar a um amigo, indique o site para que ele possa sempre
baixar as ltimas verses. Voc pode conferir o cdigo de verso da apostila logo no fnal do ndice.
Baixe sempre a verso mais nova em: www.caelum.com.br/apostilas
Esse material parte integrante do treinamento C e Orientao a Objetos e distribudo gratuitamente exclu-
sivamente pelo site da Caelum. Todos os direitos so reservados Caelum. A distribuio, cpia, revenda e
utilizao para ministrar treinamentos so absolutamente vedadas. Para uso comercial deste material, por
favor, consulte a Caelum previamente.
www.caelum.com.br

Sumrio
Como aprender C
. O que realmente importante? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Sobre os exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Tirando dvidas e indo alm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
O que C e .Net
. Um pouco sobre a histria do C e .Net . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Mquina virtual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Execuo do cdigo na CLR e o JIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. O ambiente de desenvolvimento do C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Executando aplicaes sem o Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. O primeiro programa em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. O que aconteceu durante a execuo? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Variveis e tipos primitivos
. Operaes com variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Tipos Primitivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Armazenando texto em variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Documentando o cdigo atravs de comentrios . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Estruturas de controle
. Tomando decises no cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Mais sobre condies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios opcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Estruturas de repetio
. Repetindo um bloco de cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais do while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais incremento e decremento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Classes e objetos
. Organizando o cdigo com Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Extraindo comportamentos atravs de mtodos . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Devolvendo valores de dentro do mtodo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Valor padro dos atributos da classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Mais um exemplo: Transfere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Conveno de nomes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
i
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Composio de classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Encapsulamento e Modifcadores de Acesso
. Encapsulamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Controlando o acesso com properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Simplifcando a declarao de propriedades com Auto-Implemented Properties . . . . . . . .
. Conveno de nome para property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais: Visibilidade Internal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Construtores
. Mltiplos construtores dentro da classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais Initializer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Introduo ao Visual Studio com Windows Form
. Introduo prtica aos atalhos do Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . .
. A classe Convert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Operaes na conta: saque e depsito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Controlando o nome da ao de um boto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Renomeando Variveis, Mtodos e Classes com o Visual Studio . . . . . . . . . . . . . . . . . .
. Para saber mais organizando o formulrio com Label e GroupBox . . . . . . . . . . . . . . .
. Resumo dos atalhos do Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais tipos implcitos e a palavra VAR . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios Opcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Herana
. Reaproveitando cdigo com a Herana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Reaproveitando a implementao da classe base . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Polimorfsmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais o que herdado? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Trabalhando com arrays
. Para saber mais inicializao de Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Organizando as contas com o ComboBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Cadastro de novas contas
. Utilizando o AdicionaConta no load do formulrio . . . . . . . . . . . . . . . . . . . . . . . . .
ii
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Classes abstratas
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Interfaces
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Mtodos e atributos estticos
. Exerccios Opcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais classes estticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Excees
. Retorno do mtodo para controlar erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Controlando erros com excees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Tratando mltiplas excees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Namespaces
. Para saber mais - Declarao de namespace aninhados . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais - Alias para namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Classe Object
. Implementando a comparao de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Melhorando a implementao do Equals com o is . . . . . . . . . . . . . . . . . . . . . . . . . .
. Integrando o Object com o ComboBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Trabalhando com listas
. Facilitando o trabalho com colees atravs das listas . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Lidando com conjuntos
. Otimizando a busca atravs de conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Conjuntos Ordenados com o SortedSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. A interface de todos os conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Comparao entre listas e conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Buscas rpidas utilizando Dicionrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Iterando no dicionrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
LINQ e Lambda
iii
. Filtros utilizando o LINQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Simplifcando a declarao do lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Outros mtodos do LINQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Utilizando o LINQ com outros tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Melhorando as buscas utilizando a sintaxe de queries . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais projees e objetos annimos . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Ordenando colees com LINQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios - Ordenao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
System.IO
. Leitura de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Escrevendo em arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Gerenciando os arquivos com o using . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. Para saber mais onde colocar os arquivos da aplicao . . . . . . . . . . . . . . . . . . . . . .
Manipulao de strings
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Apndice estendendo comportamentos atravs de mtodos extras
. Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ndice Remissivo
Verso: ..
iv
C
Como aprender C
. Oqcv v nvntmvN1v :mvon1nN1v:
Muitos livros, ao passar dos captulos, mencionam todos os detalhes da linguagem, juntamente com seus
princpios bsicos. Isso acaba criando muita confuso, em especial porque o estudante no consegue dife-
renciar exatamente o que essencial aprender no incio, daquilo que pode ser deixado para estudar mais
tarde.
Se uma classe abstrata deve ou no ter ao menos um mtodo abstrato, se o if somente aceita argumentos
booleanos e todos os detalhes sobre classes internas, realmente no devemser preocupaes para aquele cujo
objetivo primrio aprender C. Esse tipo de informao ser adquirida com o tempo e no necessria no
incio.
Neste curso, separamos essas informaes em quadros especiais, j que so informaes extra. Ou ento,
apenas citamos em algum exerccio e deixamos para o leitor procurar informaes adicionais, se for de seu
interesse.
Por fm, falta mencionar algo sobre a prtica, que deve ser tratada seriamente: todos os exerccios so muito
importantes e os desafos podem ser feitos aps o trmino do curso. De qualquer maneira, recomendamos
aos alunos estudarem em casa e praticarem bastante cdigo e variaes.
. Sonnv os vxvncc:os
Os exerccios do curso variam, de prticos at pesquisas na internet, ou mesmo consultas sobre assuntos
avanados em determinados tpicos, para incitar a curiosidade do aprendiz na tecnologia.
Existe tambm, emdeterminados captulos, uma srie de desafos. Eles focammais no problema computaci-
onal que na linguagem, porm so uma excelente forma de treinar a sintaxe e, principalmente, familiarizar o
Material do Treinamento C e Orientao a Objetos
aluno com as bibliotecas padro do C, alm de proporcionar um ganho na velocidade de desenvolvimento.
. T:nnNoo ov:ons v :Noo ntvm
Para tirar dvidas de exerccios, ou de C em geral, recomendamos o frum do GUJ Respostas:
http://www.guj.com.br
L sua dvida ser respondida prontamente. OGUJ foi fundado por desenvolvedores da Caelume hoje conta
com mais de um milho de mensagens.
O principal recurso ofcial para encontrar documentao, tutoriais e at mesmo livros sobre .NET e C a
Microsof Developers Network, ou MSDN:
http://msdn.microsof.com
Destacamos a seo de tutoriais de C (em ingls), no endereo:
http://msdn.microsof.com/en-us/library/aa.aspx
H tambm fruns ofciais em portugus na MSDN:
http://social.msdn.microsof.com/Forums/pt-br/home
Fora isso, sinta-se vontade para entrar emcontato comseuinstrutor para tirar todas as dvidas que surgirem
durante o curso.
Se o que voc est buscando so livros de apoio, sugerimos conhecer a editora Casa do Cdigo:
http://www.CasaDoCodigo.com.br
Em lngua portuguesa, h alguns livros sobre o assunto:
Andrew Stellman. Use a Cabea! C. Edio. Alta Books.
http://www.altabooks.com.br/use-a-cabeca-c-a-edicao.html
Harvey Deitel, Paul Deitel. C Como Programar. Edio. Pearson.
http://www.pearson.com.br/produtos_detalhes.asp?id_p=&livro_cod=
Em lngua inglesa, h uma edio bem mais atual do ltimo livro:
Harvey Deitel, Paul Deitel. Visual C How to Program. th Edition. Prentice Hall.
http://www.deitel.com/Books/C/VisualCHowtoProgram/tabid//Default.aspx
ACaelumoferece outros cursos de C/.NET, comdestaque para o FN-, que traz a aplicao do C na Web:
http://www.caelum.com.br
Captulo - Como aprender C - Tirando dvidas e indo alm - Pgina
Material do Treinamento C e Orientao a Objetos
H tambm cursos online que vo ajud-lo a ir alm, com muita interao com os instrutores:
http://www.Alura.com.br
Captulo - Como aprender C - Tirando dvidas e indo alm - Pgina
C
O que C e .Net
. Umvocco sonnv n n:s1on:n oo C v .Nv1
Entender umpouco da histria do C e do .Net essencial para enxergar os motivos que a levaramao sucesso.
No fnal da dcada de a Microsof tinha diversas tecnologias e linguagens de programao para resolver
muitos problemas diferentes. Toda vez que um programador precisava migrar para uma nova linguagem,
era necessrio aprender tanto a nova linguagem quanto suas bibliotecas e conceitos. Para solucionar esses
problemas, a Microsof recorreu linguagem Java.
OJava agradou os engenheiros da Microsof pois comela podamos construir programas que eramindepen-
dentes do ambiente de execuo, alm de possuir diversas bibliotecas com solues prontas para diversos
problemas. Para lanar produtos baseados no Java, a Microsof assinou um acordo de licenciamento com a
Sun para utilizar o Java em ambiente Windows.
Porm, a linguagem Java possua um grave problema: ela no se comunicava bem com o as bibliotecas de
cdigo nativo (cdigo de mquina) que j existiam. Para resolver isso, a Microsof decidiu criar a sua pr-
pria implementao do Java chamado J++ que possua extenses proprietrias que resolviam o problema de
comunicao com o cdigo nativo existente. Para o desenvolvimento dessa nova implementao do Java,
a Microsof contratou um engenheiro chamado Anders Hejlsberg, um dos principais nomes por trs do
Delphi.
O J++ era uma verso da linguagem Java que s podia ser executada no ambiente Microsof. Seu cdigo no
podia ser executado em mais nenhum ambiente Java, o que violava o licenciamento feito com a Sun e, por
isso, a Microsof foi processada. Uma das mais conhecidas batalhas judiciais da poca.
Sem o J++, a Microsof foi obrigada a repensar sua estratgia sobre como lidar com as diferentes linguagens
e tecnologias utilizadas internamente. A empresa comeou a trabalhar em um nova plataforma que seria a
Material do Treinamento C e Orientao a Objetos
base de todas as suas solues, que posteriormente foi chamada de .Net. Esse novo ambiente de desenvol-
vimento da Microsof foi desde o incio projetado para trabalhar com diversas linguagens de programao,
assim diversas linguagens diferentes compartilhariam o mesmo conjunto de bibliotecas. Com isso, para um
programador migrar de uma linguagem para outra ele precisaria apenas aprender a linguagem sem se preo-
cupar com as bibliotecas e APIs.
Alm de uma plataforma a Microsof tambm precisava de uma linguagem de programao. Um novo pro-
jeto de linguagem de programao foi iniciado, o projeto COOL (C-like Object Oriented Language). Anders
Hejlsberg foi escolhido como engenheiro chefe desse novo projeto. COOL teve seu design baseado em di-
versas outras linguagens do mercado como Java, C, C++, Smalltalk, Delphi e VB. A ideia era estudar os
problemas existentes e incorporar solues.
Em , o projeto COOL foi lanado como linguagem C . junto com o ambiente .Net .. Atualmente
a linguagem C est em sua verso . e o .Net na verso .., tendo evoludo com expressiva velocidade,
adotando novidades na sua sintaxe que a diferenciaram bastante do Java e outras concorrentes.
. MKqc:Nn v:n1cnt
Emuma linguagemde programao como Ce Pascal, temos a seguinte situao quando vamos compilar um
programa:
O cdigo fonte compilado para cdigo de mquina especfco de uma plataforma e sistema operacional.
Muitas vezes o prprio cdigo fonte desenvolvido visando uma nica plataforma!
Esse cdigo executvel (binrio) resultante ser executado pelo sistema operacional e, por esse motivo, ele
deve saber conversar com o sistema operacional em questo. Isto , temos um cdigo executvel diferente
para cada sistema operacional diferente.
Precisamos reescrever um mesmo pedao da aplicao para diferentes sistemas operacionais, j que eles no
so compatveis.
O C utiliza o conceito de mquina virtual. Entre o sistema operacional e a aplicao existe uma camada
extra responsvel por traduzir mas no apenas isso o que sua aplicao deseja fazer para as respectivas
chamadas do sistema operacional onde ela est rodando no momento.
Repare que uma mquina virtual umconceito bemmais amplo que o de uminterpretador. Como o prprio
nome diz, uma mquina virtual como um computador de mentira": tem tudo que um computador tem.
Em outras palavras, ela responsvel por gerenciar memria, threads, a pilha de execuo etc.
Sua aplicao roda semnenhumenvolvimento como sistema operacional! Sempre conversando apenas com
a mquina virtual do C, a Common Language Runtime (CLR). A CLR o ambiente de execuo para todas
as linguagens da plataforma .Net, no apenas para o C. Certamente isso no foi uma revoluo. O Java
trouxe esse conceito para o mercado e j havia muitas linguagens com esses recursos, apesar de que eram
encontradas mais no meio acadmico.
Captulo - O que C e .Net - Mquina virtual - Pgina
Material do Treinamento C e Orientao a Objetos
O CLR isola totalmente a aplicao do sistema operacional. Se uma aplicao rodando no CLR termina
abruptamente, ela no afetar as outras mquinas virtuais e nem o sistema operacional. Essa camada de
isolamento tambm interessante quando pensamos emumservidor que no pode se sujeitar a rodar cdigo
que possa interferir na boa execuo de outras aplicaes.
Como a mquina virtual deve trabalhar comdiversas linguagens de programao diferentes, a CLRno pode
executar diretamente o cdigo do C, ela precisa executar uma linguagem intermediria comum a todas as
linguagens da plataforma .Net, a CIL (Common Intermediate Language). Para gerar o CIL que ser executado
pela CLR, precisamos passar o cdigo C por um compilador da linguagem, como o programa csc.exe. O
compilador l o arquivo com o cdigo fonte do programa e o traduz para o cdigo intermedirio que ser
executado pela mquina virtual.
CommoN LnNccncv INvnns1ncc1cnv
A infraestrutura necessria para executar os cdigos escritos para a plataforma .Net chamada
de CLI (Common Language Infrastructure). A CLI engloba a mquina virtual do C (CLR), a
linguagem intermediria (CIL) e os tipos base utilizados nos programas.
. ExvccXo oo coo:co Nn CLR v o JIT
Para executarmos uma aplicao C, precisamos passar o cdigo CIL do programa para a CLR, a mquina
virtual do .Net. A CLR por sua vez precisa executar o cdigo da aplicao no sistema operacional do usurio
e, para isso, precisa emitir o cdigo de mquina correto para o ambiente em que o programa est sendo
executado. Mas a CLR no interpreta o CIL do programa, isso seria muito lento, ao invs disso, quando
o programa C carregado na memria, a CLR converte automaticamente o cdigo CIL para cdigo de
mquina, esse processo feito por um compilador Just in Time (JIT) da CLR.
Esse carregamento utilizando o JITfaz comque o cdigo escrito na linguagemC execute como desempenho
mximo, o mesmo de um programa escrito em linguagens que compilam diretamente para o cdigo de
mquina, mas com a vantagem de executar no ambiente integrado do .Net.
. Onmn:vN1v ov ovsvNvotv:mvN1o oo C
Nesse curso escreveremos todo o cdigo utilizando o Visual Studio Express Edition, a verso gratuita da
ferramenta de desenvolvimento de aplicaes distribuda pela prpria Microsof. Apesar das explicaes
serem feitas com base na verso express, tudo funcionar da mesma forma dentro das verses pagas da
ferramenta.
O Visual Studio Express Edition pode ser encontrado no site:
http://bit.ly/1fb6Ay8
Captulo - O que C e .Net - Execuo do cdigo na CLR e o JIT - Pgina
Material do Treinamento C e Orientao a Objetos
A verso que utilizaremos na apostila a Visual Studio for Windows Desktop.
Durante a instalao do Visual Studio, o .Net Framework tambm ser automaticamente instalado em sua
mquina, ento ela estar pronta executar as aplicaes escritas em C.
. Exvcc1nNoo nvt:cnovs svmo V:scnt S1co:o
Como vimos anteriormente, para executarmos uma aplicao C precisamos da mquina virtual da lin-
guagem alm das bibliotecas do .Net Framework. Ao instalarmos o Visual Studio, todo esse ambiente de
execuo de programas automaticamente instalado em nossas mquinas, mas e se quisermos executar o
programa em um computador que no tenha o Visual Studio instalado, o computador de um cliente, por
exemplo?
Nesse caso precisamos instalar apenas o ambiente de execuo no computador do cliente. Para isso podemos
utilizar um pacote de instalao fornecido pela prpria Microsof, esses so os .Net Framework Redistribu-
table. O pacote de instalao para a ltima verso do .Net Framework (.. lanada em ) pode ser
encontrada no seguinte site:
http://www.microsoft.com/en-us/download/details.aspx?id=40779
C vmoc1nos nmn:vN1vs
Podemos tambm executar o cdigo C dentro de ambientes no windows utilizando imple-
mentaes livres do Common Language Infrastructure. Uma implementao do ambiente de
execuo para ambientes no Windows o Mono:
http://www.mono-project.com/Main_Page
. Ovn:mv:no vnocnnmn vmC
Agora que j entendemos o funcionamento da linguagem C, vamos comear a desenvolver a primeira apli-
cao utilizando o Visual Studio. Para criarmos um programa C utilizando o Visual Studio precisamos
inicialmente de um novo projeto.
Dentro do Visual Studio , aperte o atalho Ctrl + Shift + N para abrir o assistente de criao de novo
projeto.
Captulo - O que C e .Net - Executando aplicaes sem o Visual Studio - Pgina
Material do Treinamento C e Orientao a Objetos
No canto esquerdo da janela do assistente de criao de novo projeto, podemos escolher a linguagem de
programao que desejamos utilizar, escolha a opo Visual C. Como tipo de projeto escolha a opo
Windows Form Application, com isso estamos criando um novo projeto de interface grfca utilizando o
C.
No canto inferior da janela, podemos escolher o nome do projeto almda pasta emque ele ser armazenado.
Utilizaremos ProjetoInicial como nome desse novo projeto.
Captulo - O que C e .Net - O primeiro programa em C - Pgina
Material do Treinamento C e Orientao a Objetos
Queremos inicialmente colocar umboto no formulrio que, quando clicado, abrir uma caixa de mensagem
do Windows.
Para colocarmos o boto no formulrio, precisamos abrir uma nova janela do Visual Studio chamada Tool-
box, que fca no canto esquerdo da janela do formulrio. O Toolbox tambm pode ser aberto utilizando-se
o atalho Ctrl + W, X. Dentro da janela do Toolbox, no grupo Common Controls, clique no componente
button e arraste-o para o formulrio.
Agora d um duplo clique no boto que acabamos de adicionar para programarmos o que deve acontecer
quando o boto for clicado. O Visual Studio abrir o cdigo do formulrio. No se preocupe com todo o
cdigo complicado que est escrito nesse arquivo, entenderemos o signifcado de cada uma dessas linhas
mais a frente no curso.
Captulo - O que C e .Net - O primeiro programa em C - Pgina
Material do Treinamento C e Orientao a Objetos
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace form
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}
O trecho de cdigo que nos interessa no momento :
private void button1_Click(object sender, EventArgs e)
{
}
Todo cdigo que for colocado dentro das chaves ser executado quando o boto for clicado.
No clique do boto, queremos executar o comando que mostra uma caixa de mensagens para o usurio.
MessageBox.Show(mensagem)
No C, todo comando deve ser terminado pelo caractere ;. Portanto, o cdigo para mostrar a caixa de
mensagem fca da seguinte forma:
MessageBox.Show(mensagem);
Queremos que, ao clicar no boto, a mensagemHello World seja exibida emuma caixa de mensagens. Ento,
utilizaremos o seguinte cdigo:
Captulo - O que C e .Net - O primeiro programa em C - Pgina
Material do Treinamento C e Orientao a Objetos
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(Hello World);
}
Como a mensagem somente um texto, o compilador do C nos fora a coloc-la entre aspas duplas. Por-
tanto, o cdigo do clique do boto fcar assim:
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello World");
}
O cdigo completo fca:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace form
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello World");
}
}
}
No se preocupe com as linhas de cdigo que no foram explicadas. Entenderemos o que elas fazem durante
o curso.
Aperte F5 para executar o cdigo do formulrio. O resultado deve ser algo parecido com a imagem a seguir:
Captulo - O que C e .Net - O primeiro programa em C - Pgina
Material do Treinamento C e Orientao a Objetos
. Exvncc:os
) Qual a mensagem que ser exibida na caixa de texto criada pelo seguinte cdigo?
MessageBox.Show("Curso de C# da Caelum");
Hello World
Curso de C da Caelum
Ol Mundo
Caelum
Nenhuma das opes
. Oqcv ncoN1vcvc ocnnN1v n vxvccXo:
Vimos que quando apertamos a tecla F do teclado dentro do Visual Studio, nosso programa executado.
Agora vamos entender o que aconteceu.
Quando pedimos para o Visual Studio executar uma aplicao, ele chama o compilador da linguagem C
passando os arquivos de texto que contm o cdigo da aplicao (cdigo fonte do programa). Caso o c-
digo fonte no tenha nenhum erro de sintaxe, o compilador gera o cdigo intermedirio (CIL, Common
Intermediate Language) que entendido pela mquina virtual da linguagemC, a CLR (Common Language
Runtime). O cdigo CIL colocado em um arquivo executvel (arquivo com extenso .exe) dentro da pasta
do projeto. Esse arquivo que resultado da compilao do programa chamado de Assembly dentro da
linguagem C.
Depois da compilao, o Visual Studio executa o assembly gerado na mquina virtual do C. A CLR por sua
vez carrega o cdigo CIL que foi gerado pelo compilador e o executa no sistema operacional, mas se a CLR
Captulo - O que C e .Net - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
interpretasse o cdigo CIL para linguagem de mquina, o desempenho do C no seria muito bom, e por
isso, quando um programa C carregado pela CLR ele j automaticamente convertido para linguagem de
mquina por um processo conhecido como JIT (Just-in-time). Ento no C, o cdigo sempre executado
com o mesmo desempenho do cdigo de mquina.
Captulo - O que C e .Net - O que aconteceu durante a execuo? - Pgina
C
Variveis e tipos primitivos
Na maioria dos programas que escrevemos, no estamos interessados emapenas mostrar uma caixa de men-
sagens para o usurio. Queremos tambm armazenar e processar informaes.
Em um sistema bancrio, por exemplo, estaramos interessados em armazenar o saldo de uma conta e o
nome do correntista. Para armazenar esses dados, precisamos pedir para o C reservar regies de memria
que sero utilizadas para armazenar informaes. Essas regies de memria so conhecidas como variveis.
As variveis guardaminformaes de umtipo especfco. Podemos, por exemplo, guardar umnmero inteiro
representando o nmero da conta, umtexto para representar o nome do correntista ou um nmero real para
representar o saldo atual da conta. Para utilizar uma varivel, devemos primeiramente declar-la no texto
do programa.
Na declarao de uma varivel, devemos dizer seu tipo (inteiro, texto ou real, por exemplo) e, alm disso,
qual o nome que usaremos para referenci-la no texto do programa. Para declarar uma varivel do tipo
inteiro que representa o nmero de uma conta, utilizamos o seguinte cdigo:
int numeroDaConta;
Repare no ; no fnal da linha. Como a declarao de uma varivel um comando da linguagem C, precisa-
mos do ; para termin-lo.
Alm do tipo int (para representar inteiros), temos tambm os tipos double e float (para nmeros reais),
string (para textos), entre outros.
Depois de declarada, uma varivel pode ser utilizada para armazenar valores. Por exemplo, se estivssemos
interessados em guardar o valor 1 na varivel numeroDaConta que declaramos anteriormente, utilizaramos
o seguinte cdigo:
numeroDaConta = 1;
Material do Treinamento C e Orientao a Objetos
L-se numeroDaConta recebe . Quando, no momento da declarao da varivel, sabemos qual ser seu
valor, podemos utilizar a seguinte sintaxe para declarar e atribuir o valor para a varivel.
double saldo = 100.0;
. Ovvnnovs comvnn:Kvv:s
Agora que j sabemos como guardar informaes no programa, estamos interessados emexecutar operaes
nesses valores. Pode ser interessante para um correntista saber qual ser o saldo de sua conta aps um saque
de reais. Para realizar essa operao, devemos subtrair reais do saldo da conta:
double saldo = 100.0;
saldo = saldo - 10.0;
Nesse cdigo, estamos guardando na varivel saldo o valor da conta 100.0 (saldo antigo) menos 10.0 ento
seu valor fnal ser de 90.0. Da mesma forma que podemos subtrair valores, podemos tambm fazer somas
(com o operador +), multiplicaes (operador *) e divises (operador /).
Podemos ainda guardar o valor do saque em uma varivel:
double saldo = 100.0;
double valorDoSaque = 10.0;
saldo = saldo - valorDoSaque;
Depois de realizar o saque, queremos mostrar para o usurio qual o saldo atual da conta. Para mostrarmos
essa informao, utilizaremos novamente o MessageBox.Show:
MessageBox.Show("O saldo da conta aps o saque : " + saldo);
Veja que, no cdigo do saque, estamos repetindo o nome da varivel saldo dos dois lados da atribuio.
Quando temos esse tipo de cdigo, podemos utilizar uma abreviao disponibilizada pelo C, o operador
-=:
double saldo = 100.0;
double valorDoSaque = 10.0;
saldo -= valorDoSaque;
Quando o compilador do C encontra o saldo -= valorDoSaque, essa linha traduzida para a forma que
vimos anteriormente: saldo = saldo - valorDoSaque. Alm do -=, temos tambm os operadores += (para
somas), *= (para multiplicaes) e /= (para divises).
Captulo - Variveis e tipos primitivos - Operaes com variveis - Pgina
Material do Treinamento C e Orientao a Objetos
. T:vos Pn:m:1:vos
Vimos que no C toda varivel possui umtipo, utilizamos o int quando queremos armazenar valores inteiros
e double para nmeros reais. Agora vamos descobrir quais so os outros tipos de variveis do C.
Os tipos listados nessa tabela so conhecidos como tipos primitivos ou value types da linguagem C. Toda
vez que atribumos umvalor para uma varivel de umtipo primitivo, o C copia o valor atribudo para dentro
da varivel.
Agora que conhecemos os tipos primitivos da linguagem C, vamos ver como que eles interagem dentro
de uma aplicao. Suponha que temos um cdigo que declara uma varivel do tipo inteiro e depois tenta
copiar seu contedo para uma varivel long:
int valor = 1;
long valorGrande = valor;
Nesse caso, como o tamanho de uma varivel long maior do que o de uma varivel int, o C sabe que
podemos copiar o seu contedo sem perder informaes e, por isso, esse um cdigo que compila sem
nenhum erro. Agora vamos tentar copiar o int para uma varivel do tipo short:
int valor = 1;
short valorPequeno = valor;
Captulo - Variveis e tipos primitivos - Tipos Primitivos - Pgina
Material do Treinamento C e Orientao a Objetos
Nesse cdigo, tentamos copiar o contedo de uma varivel maior para dentro de uma de tamanho menor.
Essa cpia pode ser perigosa pois o valor que est na varivel do tipo int pode no caber na varivel short
e, por isso, o compilador do C gera um erro de compilao quando tentamos fazer essa converso.
Para forarmos o compilador do C a fazer uma converso perigosa, precisamos utilizar uma operao do
C chamada casting falando para qual tipo queremos fazer a converso.
int valor = 1;
short valorPequeno = (short) valor;
. AnmnzvNnNoo 1vx1o vmvnn:Kvv:s
Alm dos tipos primitivos, o C tambm possui um tipo especfco para armazenar textos. No tipo string,
podemos guardar qualquer valor que seja delimitado por aspas duplas, por exemplo:
string mensagem = "Minha Mensagem";
MessageBox.Show(mensagem);
Podemos juntar o valor de duas variveis do tipo string utilizando o operador + da linguagem. A soma de
strings uma operao conhecida como concatenao.
string mensagem = "Ol ";
string nome = "victor";
MessageBox.Show(mensagem + nome);
Esse cdigo imprime o texto Ol victor emuma caixa de mensagens. Podemos utilizar a concatenao para
adicionar o contedo de qualquer varivel em uma string:
int idade = 25;
string mensagem = "sua idade : " + idade;
MessageBox.Show(mensagem);
Esse segundo cdigo imprime o texto sua idade : 25.
. DoccmvN1nNoo o coo:co n1nnvvs ov comvN1Kn:os
Quando queremos documentar o signifcado de algumcdigo dentro de umprograma C, podemos utilizar
comentrios. Para fazermos um comentrio de uma linha, utilizamos o //. Tudo que estiver depois do //
considerado comentrio e, por isso, ignorado pelo compilador da linguagem.
Captulo - Variveis e tipos primitivos - Armazenando texto em variveis - Pgina
Material do Treinamento C e Orientao a Objetos
double saldo = 100.0; // Isso um comentrio e ser ignorado pelo compilador
Muitas vezes precisamos escrever diversas linhas de comentrios para, por exemplo, documentar uma lgica
complexa da aplicao. Nesses casos podemos utilizar o comentrio de mltiplas linhas que inicializado
por um /* e terminado pelo */. Tudo que estiver entre a abertura e o fechamento do comentrio ignorado
pelo compilador da linguagem:
/*
Isso um comentrio
de mltiplas linhas
*/
. Exvncc:os
Faa o cdigo dos exerccios do captulo dentro de botes no formulrio do projeto inicial, cada exerccio
deve fcar na ao de um boto diferente.
) Crie variveis com as idades dos seus melhores amigos e/ou familiares. Algo como:
int idadeJoao = 10;
int idadeMaria = 25;
Em seguida, pegue essas idades e calcule a mdia delas. Exiba o resultado em um MessageBox.
) O que acontece com o cdigo abaixo?
int pi = 3.14;
O cdigo compila, e pi guarda o nmero
O cdigo compila, e pi guarda . (inteiros podem guardar casas decimais)
O cdigo no compila, pois . no cabe dentro de um inteiro
) Execute o trecho de cdigo a seguir. O que acontece com ele?
double pi = 3.14;
int piQuebrado = (int)pi;
MessageBox.Show("piQuebrado = " + piQuebrado);
Repare o (int). Estamos forando a converso do double para um inteiro.
Qual o valor de piQuebrado nesse caso?
.


Captulo - Variveis e tipos primitivos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) (Opcional) No colegial, aprendemos a resolver equaes de segundo grau usando a frmula de Bhaskara.
A frmula assim:
delta = b*b - 4*a*c;
a1 = (-b + raiz(delta)) / (2 * a);
a2 = (-b - raiz(delta)) / (2 * a);
Crie um programa com trs variveis inteiras, a, b, c, com quaisquer valores. Depois crie variveis
double, delta, a1, a2, com a frmula anterior.
Imprima a1 e a2 em um MessageBox.
Dica: Para calcular raiz quadrada, use Math.Sqrt(variavel). No se esquea que no podemos calcular
a raiz quadrada de nmeros negativos.
Captulo - Variveis e tipos primitivos - Exerccios - Pgina
C
Estruturas de controle
. TomnNoo ovc:sovs No coo:co
Voltando para nosso exemplo de aplicao bancria, queremos permitir um saque somente se o valor a ser
retirado for menor ou igual ao saldo da conta, ou seja, se o saldo da conta for maior ou igual ao valor do
saque, devemos permitir a operao, do contrrio no podemos permitir o saque. Precisamos fazer execuo
condicional de cdigo.
No C, podemos executar cdigo condicional utilizando a construo if:
if (condicao)
{
// Esse cdigo ser executado somente se a condio for verdadeira
}
No nosso exemplo, queremos executar a lgica de saque apenas se o saldo for maior ou igual ao valor do
saque:
double saldo = 100.0;
double valorSaque = 10.0;
if (saldo >= valorSaque)
{
// cdigo do saque.
}
O cdigo do saque deve diminuir o saldo da conta e mostrar uma mensagem para o usurio indicando que
o saque ocorreu com sucesso:
Material do Treinamento C e Orientao a Objetos
double saldo = 100.0;
double valorSaque = 10.0;
if (saldo >= valorSaque)
{
saldo = saldo - valorSaque;
MessageBox.Show("Saque realizado com sucesso");
}
Repare que, se a conta no tiver saldo sufciente para o saque, o usurio no avisado. Ento estamos na
seguinte situao: Se a conta tiver saldo sufciente, quero fazer o saque, seno, quero mostrar a mensagem
Saldo Insufciente para o usurio. Para fazer isso, podemos usar o else do C:
if (saldo >= valorSaque)
{
// cdigo do saque
}
else
{
MessageBox.Show("Saldo Insuficiente");
}
. Mn:s sonnv coNo:ovs
Repare na expresso que passamos para o if: saldo >= valorSaque. Nele, utilizamos o operador maior ou
igual. Alm dele, existem outros operadores de comparao que podemos utilizar: maior (>), menor (<),
menor ou igual (<=), igual (==) e diferente (!=). Podemos tambm negar uma condio de um if utilizando
o operador ! na frente da condio que ser negada.
No captulo anterior, vimos que um valor tem um tipo associado em C: 10 um int, "mensagem" uma
string. Da mesma forma, a expresso saldo >= valorSaque tambm tem um tipo associado: o tipo bool,
que pode assumir os valores true (verdadeiro) ou false (falso). Podemos inclusive guardar um valor desse
tipo numa varivel:
bool podeSacar = (saldo >= valorSaque);
Tambm podemos realizar algumas operaes com valores do tipo bool. Podemos, por exemplo, verifcar se
duas condies so verdadeiras ao mesmo tempo usando o operador && (AND) para fazer um e lgico:
bool realmentePodeSacar = (saldo >= valorSaque) && (valorSaque > 0);
Quando precisamos de um OU lgico, utilizamos o operador ||:
Captulo - Estruturas de controle - Mais sobre condies - Pgina
Material do Treinamento C e Orientao a Objetos
// essa condio verdadeira se (saldo >= valorSaque) for true
// ou se (valorSaque > 0) for verdadeiro.
bool realmentePodeSacar = (saldo >= valorSaque) || (valorSaque > 0);
Assim, podemos construir condies mais complexas para um if. Por exemplo, podemos usar a varivel
realmentePodeSacar declarada no if que verifca se o cliente pode sacar ou no:
if (realmentePodeSacar)
{
// cdigo do saque
}
else
{
MessageBox.Show("Saldo Insuficiente");
}
. Exvncc:os ovc:oNn:s
) Qual a mensagem e o valor da varivel saldo aps a execuo do seguinte cdigo?
double saldo = 100.0;
double valorSaque = 10.0;
if (saldo >= valorSaque)
{
saldo -= valorSaque;
MessageBox.Show("Saque realizado com sucesso");
}
else
{
MessageBox.Show("Saldo Insuficiente");
}
mensagem: Saque realizado com sucesso; saldo: .
mensagem: Saldo Insufciente; saldo .
mensagem: Saque realizado com sucesso; saldo: .
mensagem: Saldo Insufciente; saldo .
mensagem: Saque realizado com sucesso; saldo: .
) Qual a mensagem e o valor da varivel saldo aps a execuo do seguinte cdigo?
double saldo = 5.0;
double valorSaque = 10.0;
Captulo - Estruturas de controle - Exerccios opcionais - Pgina
Material do Treinamento C e Orientao a Objetos
if (saldo >= valorSaque)
{
saldo -= valorSaque;
MessageBox.Show("Saque realizado com sucesso");
}
else
{
MessageBox.Show("Saldo Insuficiente");
}
mensagem: Saque realizado com sucesso; saldo: -.
mensagem: Saldo Insufciente; saldo -.
mensagem: Saque realizado com sucesso; saldo: .
mensagem: Saldo Insufciente; saldo .
mensagem: Saque realizado com sucesso; saldo: .
) Em alguns casos, podemos ter mais de duas decises possveis. O banco pode, por exemplo, decidir que
contas com saldo menor que R pagam de taxa de manuteno, contas com saldo entre R
e R pagam e contas com saldo maior que R pagam .
Para representar esse tipo de situao, podemos usar o else if do C, que funciona em conjunto com o
if que j conhecemos. Veja como fcaria a situao descrita anteriormente:
double taxa;
if (saldo < 1000)
{
taxa = 0.01;
}
else if (saldo <= 5000)
{
taxa = 0.05;
}
else
{
taxa = 0.1;
}
O C vai processar as condies na ordem, at encontrar uma que seja satisfeita. Ou seja, na segunda
condio do cdigo, s precisamos verifcar que saldo menor ou igual a R pois, pois se o C
chegar nessa condio porque ele no entrou no primeiro if, isto , sabemos que o saldo maior ou
igual a R nesse ponto.
Com base nisso, qual vai ser a mensagem exibida pelo cdigo seguinte?
Captulo - Estruturas de controle - Exerccios opcionais - Pgina
Material do Treinamento C e Orientao a Objetos
double saldo = 500.0;
if (saldo < 0.0)
{
MessageBox.Show("Voc est no negativo!");
}
else if (saldo < 1000000.0)
{
MessageBox.Show("Voc um bom cliente");
}
else
{
MessageBox.Show("Voc milionrio!");
}
Voc est no negativo!
Voc um bom cliente
Nenhuma mensagem
Voc milionrio!
Voc um bom cliente, seguida de Voc milionrio!
) Uma pessoa s pode votar em eleies brasileiras se ela for maior que anos e for cidad brasileira. Crie
um programa com duas variveis, int idade, bool brasileira, e faa com que o programa diga se a
pessoa est apta a votar ou no, de acordo com os dados nas variveis.
) Crie um programa que tenha uma varivel double valorDaNotaFiscal e, de acordo com esse valor, o
imposto deve ser calculado. As regras de clculo so:
Se o valor for menor que , o imposto deve ser de
Se o valor estiver entre e , o imposto deve ser de .
Se o valor estiver entre e , o imposto deve ser de .
Se for maior ou igual a , o imposto deve ser de
Imprima o imposto em um MessageBox.
Captulo - Estruturas de controle - Exerccios opcionais - Pgina
C
Estruturas de repetio
. Rvvv1:Noo cmntoco ov coo:co
De volta ao exemplo da aula anterior, suponha agora que o cliente desse mesmo banco queira saber quanto
ele ganhar, ao fnal de ano, caso ele invista um valor. O investimento paga do valor investido ao ms.
Por exemplo, se o cliente investir R ,, ao fnal de meses, ter por volta de R ,: no primeiro
ms, R , + R, * = R ,; no segundo ms, R , + R, * = R ,;
e assim por diante. Ou seja, para calcular o quanto ele ter ao fnal de um ano, podemos multiplicar o valor
investido vezes por .
Para resolvermos esse problema, precisamos fazer uso de uma estrutura de controle que repete um determi-
nado bloco de cdigo at que uma condio seja satisfeita. Essa estrutura recebe o nome de loop.
Para fazer um loop no C, utilizaremos, inicialmente, a instruo for. O for uma instruo que possui trs
partes:
Aprimeira parte a inicializao, na qual podemos declarar e inicializar uma varivel que ser utilizada
no for;
A segunda parte a condio do loop. Enquanto a condio do loop for verdadeira, o loop continuar
executando;
A terceira parte a atualizao, na qual podemos atualizar as variveis que so utilizadas pelo for.
Cada uma das partes do for separada por um ;.
for (inicializao; condio; atualizao)
{
// Esse cdigo ser executado enquanto a condio for verdadeira
}
Material do Treinamento C e Orientao a Objetos
Veja o cdigo a seguir, por exemplo, em que usamos um for que repetir o clculo vezes:
double valorInvestido = 1000.0;
for (int i = 1; i <= 12; i += 1)
{
valorInvestido = valorInvestido * 1.01;
}
MessageBox.Show("Valor investido agora " + valorInvestido);
Veja que nosso for comea inicializando a varivel i com e repete o cdigo de dentro dele enquanto o valor
de i for menor ou igual a , ou seja, ele s para no momento em que i for maior do que . E veja que, a
cada iterao desse loop, o valor de i cresce (i += 1). No fm, o cdigo de dentro do for ser repetido
vezes, como precisvamos.
O mesmo programa poderia ser escrito utilizando-se um while, em vez de um for:
double valorInvestido = 1000.0;
int i = 1;
while (i <= 12)
{
valorInvestido = valorInvestido * 1.01;
i += 1;
}
MessageBox.Show("Valor investido agora " + valorInvestido);
. Pnnn snnvn mn:s oo wn:tv
No C quando utilizamos o while, a condio do loop checada antes de todas as voltas (iteraes) do lao,
mas e se quisssemos garantir que o corpo do lao seja executado pelo menos uma vez? Nesse caso, podemos
utilizar um outro tipo de lao do V que o do while:
do
{
// corpo do loop
}
while(condio);
Com o do while a condio do loop s checada no fm da volta, ou seja, o corpo do loop executado e
depois a condio checada, ento o corpo do do...while sempre executado pelo menos uma vez.
. Pnnn snnvn mn:s :NcnvmvN1o v ovcnvmvN1o
Quando queremos incrementar o valor de uma varivel inteira em uma unidade, vimos que temos opes:
Captulo - Estruturas de repetio - Para saber mais do while - Pgina
Material do Treinamento C e Orientao a Objetos
int valor = 1;
valor = valor + 1;
// ou
valor += 1;
Porm, como incrementar o valor de uma varivel uma atividade comumna programao, o C nos oferece
o operador ++ para realizar esse trabalho:
int valor = 1;
valor++;
Temos ainda o operador -- que realiza o decremento de uma varivel.
. Exvncc:os
) Qual o valor exibido no seguinte cdigo:
int total = 2;
for (int i = 0; i < 5; i += 1)
{
total = total * 2;
}
MessageBox.Show("O total : " + total);




) Faa um programa em C que imprima a soma dos nmeros de at .
) Faa um programa em C que imprima todos os mltiplos de , entre e .
Para saber se um nmero mltiplo de , voc pode fazer if(numero % 3 == 0).
) (Opcional) Escreva um programa em C que some todos os nmeros de a , pulando os mltiplos de
. O programa deve imprimir o resultado fnal em um MessageBox.
Qual o resultado?
) (Opcional) Escreva um programa em C que imprime todos os nmeros que so divisveis por ou por
entre e .
Captulo - Estruturas de repetio - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) (Opcional) Faa um programa em C que imprima os fatoriais de a .
O fatorial de um nmero n n * n- * n- ... at n = .
O fatorial de
O fatorial de (!) * =
O fatorial de (!) * =
O fatorial de (!) * =
O fatorial de (!) * =
Faa um for que inicie uma varivel n (nmero) como e fatorial (resultado) como e varia n de at :
int fatorial = 1;
for (int n = 1; n <= 10; n++)
{
}
) (Opcional) Faa umprograma emC que imprima os primeiros nmeros da srie de Fibonacci at passar
de . A srie de Fibonacci a seguinte: , , , , , , , , etc... Para calcul-la, o primeiro elemento
vale , o segundo vale , da por diante, o n-simo elemento vale o (n-)-simo elemento somado ao
(n-)-simo elemento (ex: = + ).
) (Opcional) Faa um programa que imprima a seguinte tabela, usando fors encadeados:
1
2 4
3 6 9
4 8 12 16
n n*2 n*3 .... n*n
Captulo - Estruturas de repetio - Exerccios - Pgina
C
Classes e objetos
Neste momento, queremos representar diversas contas em nosso banco. Uma conta bancria geralmente
composta por um nmero, nome do titular e saldo. Podemos guardar essas informaes em variveis:
int numeroDaConta1 = 1;
string titularDaConta1 = "Joaquim Jos";
double saldoDaConta1 = 1500.0;
Para representar outros correntistas, precisamos de novas variveis:
int numeroDaConta2 = 2;
string titularDaConta2 = "Silva Xavier";
double saldoDaConta2 = 2500.0;
Veja que, como as informaes das contas esto espalhadas em diversas variveis diferentes, muito fcil
misturarmos essas informaes dentro do cdigo. Alm disso, imagine que antes de adicionarmos a conta
na aplicao precisamos fazer uma validao do CPFdo titular. Nesse caso precisaramos chamar uma funo
que executa essa validao, mas como podemos garantir que essa validao sempre executada?
Esses pontos listados so alguns dos problemas do estilo de programao procedural. Quando trabalha-
mos com programao procedural, os dados da aplicao fcam separados da implementao das lgicas de
negcio e, alm disso, muito difcil garantir as validaes dos dados da aplicao.
. OncnN:znNoo o coo:co comOn)v1os
Para comearmos com a orientao a objetos, vamos inicialmente pensar quais so as informaes que des-
crevem uma determinada Conta. Toda conta bancria possui um nmero, titular e saldo. Para representar-
mos a conta com essas informaes dentro do projeto, no C, precisamos criar uma classe. Dentro do C a
Material do Treinamento C e Orientao a Objetos
declarao da classe feita utilizando-se a palavra class seguida do nome da classe que queremos implemen-
tar:
class Conta
{
}
O cdigo da classe Conta, por conveno, deve fcar dentro de um arquivo com o mesmo nome da classe,
ento a classe Conta ser colocado em arquivo chamado Conta.cs.
Dentro dessa classe queremos armazenar as informaes que descrevem as contas, fazemos isso declarando
variveis dentro da classe, essas variveis so os atributos:
class Conta
{
int numero;
string titular;
double saldo;
}
Porm, para que o cdigo da aplicao possa ler e escrever nesses atributos, precisamos declar-los utilizando
a palavra public:
class Conta
{
// numero, titular e saldo so atributos do objeto
public int numero;
public string titular;
public double saldo;
}
Para utilizarmos a classe que criamos dentro de uma aplicao windows form, precisamos criar uma nova
conta no cdigo do formulrio, fazemos isso utilizando a instruo new do C:
// cdigo do formulrio
private void button1_Click(object sender, EventArgs e)
{
new Conta();
}
Quando utilizamos o new dentro do cdigo de uma classe estamos pedindo para o C criar uma nova ins-
tncia de Conta na memria, ou seja, o C alocar memria sufciente para guardar todas as informaes da
Conta dentro da memria da aplicao.
Captulo - Classes e objetos - Organizando o cdigo com Objetos - Pgina
Material do Treinamento C e Orientao a Objetos
Alm disso, o new possui mais uma funo, devolver a referncia, uma seta que aponta para o objeto em
memria, que ser utilizada para manipularmos a Conta criada. Podemos guardar essa referncia dentro de
uma varivel do tipo Conta:
// cdigo do formulrio
private void button1_Click(object sender, EventArgs e)
{
Conta c = new Conta();
}
Na memria da aplicao teremos uma situao parecida com a ilustrada na imagem a seguir:
Veja que a classe funciona como uma receita que ensina qual o formato de uma Conta dentro da aplicao.
A Conta que foi criada na memria pelo operador new chamada de instncia ou objeto.
E agora para defnirmos os valores dos atributos que sero armazenados na Conta, precisamos acessar o
objeto que vive na memria. Fazemos isso utilizando o operador . do C, informando qual o atributo que
queremos acessar. Para, por exemplo, guardarmos o valor como nmero da conta que criamos, utilizamos
o cdigo a seguir:
// cdigo do formulrio
private void button1_Click(object sender, EventArgs e)
{
Conta c = new Conta();
c.numero = 1;
}
Captulo - Classes e objetos - Organizando o cdigo com Objetos - Pgina
Material do Treinamento C e Orientao a Objetos
Com esse cdigo, estamos navegando na referncia armazenada na varivel c, e acessando o campo nmero
do objeto Conta que vive na memria. Dentro desse campo colocamos o valor . Podemos fazer o mesmo
para os outros campos da Conta:
private void button1_Click(object sender, EventArgs e)
{
Conta c = new Conta();
c.numero = 1;
c.titular = "victor";
c.saldo = 100;
}
Depois da execuo desse cdigo, teremos a seguinte situao na memria da aplicao:
Veja que, quando utilizamos umobjeto para guardar informaes, todos os atributos fcamagrupados dentro
de um nico objeto na memria, e no espalhados dentro de diversas variveis diferentes.
. Ex1nn:Noo comvon1nmvN1os n1nnvvs ov mv1ooos
Agora que conseguimos criar a primeira conta da aplicao, vamos tentar fazer algumas operaes. A pri-
meira operao que queremos implementar a operao de tirar dinheiro da conta. Para isso, como vimos
no captulo anterior, podemos utilizar o operador -= do C:
Conta c = new Conta();
c.numero = 1;
Captulo - Classes e objetos - Extraindo comportamentos atravs de mtodos - Pgina
Material do Treinamento C e Orientao a Objetos
c.titular = "victor";
c.saldo = 100;
// a conta termina com saldo de 50.0
c.saldo -= 50.0;
Mas o que aconteceria se tentssemos tirar mais 100.0 dessa conta?
c.saldo -= 100.0;
Ao executarmos essa segunda operao, a conta terminar comsaldo de -50.0, pormnesse sistema as contas
no podem fcar com saldo negativo! Portanto, antes de tirarmos dinheiro da conta, precisamos verifcar se
ela possui saldo sufciente.
if(c.saldo >= 100.0)
{
c.saldo -= 100.0;
}
Repare que teremos que copiar e colar essa verifcao em todos os pontos da aplicao em que desejamos
fazer um saque, mas o que aconteceria se fosse necessrio cobrar uma taxa em todos os saques? Teramos
que modifcar todos os pontos em que o cdigo foi copiado. Seria mais interessante isolar esse cdigo dentro
de um comportamento da Conta.
Almde atributos, os objetos tambmpodempossuir mtodos. Os mtodos so blocos de cdigo que isolam
lgicas de negcio do objeto. Ento podemos isolar a lgica do saque dentro de um mtodo Saca da classe
Conta.
Para declarar um mtodo chamado Saca na classe Conta, utilizamos a seguinte sintaxe:
class Conta
{
// declarao dos atributos
public void Saca()
{
// Implementao do mtodo
}
}
Dentro desse mtodo Saca, colocaremos o cdigo da lgica de saque.
public void Saca()
{
if(c.saldo >= 100.0)
Captulo - Classes e objetos - Extraindo comportamentos atravs de mtodos - Pgina
Material do Treinamento C e Orientao a Objetos
{
c.saldo -= 100.0;
}
}
Porm, nesse cdigo temos dois problemas: no podemos utilizar a varivel c, pois ela foi declarada no
formulrio e no dentro do mtodo e o valor do saque est constante.
Nesse mtodo Saca, queremos verifcar o saldo da conta em que o mtodo foi invocado. Para acessarmos a
referncia em que um determinado mtodo foi chamado, utilizamos a palavra this. Ento para acessarmos
o saldo da conta, podemos utilizar this.saldo:
public void Saca()
{
if(this.saldo >= 100.0)
{
this.saldo -= 100.0;
}
}
Podemos utilizar o Saca dentro do formulrio com o seguinte cdigo:
Conta c = new Conta();
// inicializa as informaes da conta
c.saldo = 100.0;
// Agora chama o mtodo Saca que foi definido na classe
c.Saca();
Agora vamos resolver o problema do valor fxo do saque. Quando queremos passar um valor para um m-
todo, precisamos passar esse valor dentro dos parnteses da chamada do mtodo:
Conta c = new Conta();
// inicializa as informaes da conta
c.saldo = 100.0;
// Agora chama o mtodo Saca que foi definido na classe
c.Saca(10.0);
Para recebermos o valor que foi passado na chamada do Saca, precisamos declarar um argumento no m-
todo. O argumento uma varivel declarada dentro dos parnteses do mtodo:
public void Saca(double valor)
{
Captulo - Classes e objetos - Extraindo comportamentos atravs de mtodos - Pgina
Material do Treinamento C e Orientao a Objetos
if(this.saldo >= valor)
{
this.saldo -= valor;
}
}
Ummtodo pode ter qualquer nmero de argumentos. Precisamos apenas separar a declarao das variveis
com uma vrgula.
. DvvotvvNoo vntonvs ov ovN1no oo mv1ooo
Agora que colocamos o mtodo Saca dentro da classe Conta, no precisamos replicar o cdigo de validao
do saque em todos os pontos do cdigo, podemos simplesmente utilizar o mtodo criado, alm disso, se
precisarmos modifcar a lgica do saque, podemos simplesmente atualizar o cdigo daquele mtodo, um
nico ponto do sistema.
Mas da forma que foi implementado, o usurio desse mtodo no sabe se o saque foi ou no bem sucedido.
Precisamos fazer com que o mtodo devolva um valor booleano indicando se a operao foi ou no bem
sucedida. Devolveremos true caso a operao seja bemsucedida e false caso contrrio. Quando ummtodo
devolve umvalor, o tipo do valor devolvido deve fcar antes do nome do mtodo emsua declarao. Quando
um mtodo no devolve valor algum, utilizamos o tipo void.
// Estamos declarando que o mtodo devolve um valor do tipo bool
public bool Saca(double valor)
{
// implementao do mtodo
}
Dentro da implementao do mtodo, devolvemos um valor utilizamos a palavra return seguida do valor
que deve ser devolvido. Ento a implementao do Saca fca da seguinte forma:
public bool Saca(double valor)
{
if(this.saldo >= valor)
{
this.saldo -= valor;
return true;
}
else
{
return false;
}
}
Captulo - Classes e objetos - Devolvendo valores de dentro do mtodo - Pgina
Material do Treinamento C e Orientao a Objetos
Quando o C executa um return, ele imediatamente devolve o valor e sai do mtodo, ento podemos sim-
plifcar a implementao do Saca para:
public bool Saca(double valor)
{
if(this.saldo >= valor)
{
this.saldo -= valor;
return true;
}
return false;
}
No formulrio podemos recuperar o valor devolvido por um mtodo.
Conta c = new Conta();
// inicializa os atributos
// Se a conta tiver saldo suficiente, deuCerto conter o valor true
// seno, ela conter false
bool deuCerto = c.Saca(100.0);
if(deuCerto)
{
MessageBox.Show("Saque realizado com sucesso");
}
else
{
MessageBox.Show("Saldo Insuficiente");
}
Ou podemos utilizar o retorno do mtodo diretamente dentro do if:
Conta c = new Conta();
// inicializa os atributos
if(c.Saca(100.0))
{
MessageBox.Show("Saque realizado com sucesso");
}
else
{
MessageBox.Show("Saldo Insuficiente");
}
Captulo - Classes e objetos - Devolvendo valores de dentro do mtodo - Pgina
Material do Treinamento C e Orientao a Objetos
. Vnton vnonXo oos n1n:nc1os on ctnssv
Agora que terminamos de implementar a lgica de saque da conta, vamos tambm implementar o mtodo
de depsito. Esse mtodo no devolver nenhum valor e receber um double como argumento:
public void Deposita(double valor)
{
this.saldo += valor;
}
No formulrio principal da aplicao, podemos inicializar o saldo inicial com o mtodo Deposita:
Conta c = new Conta();
c.Deposita(100.0);
Nesse cdigo estamos tentando depositar reais em uma conta que acabou de ser criada e o mtodo
Deposita tenta somar os . no valor inicial do atributo saldo da conta. Mas qual o valor inicial de um
atributo?
Quando declaramos uma varivel no C, ela comea com um valor indefnido, logo no podemos utiliz-
la enquanto seu valor no for inicializado, porm a linguagem trata os atributos de uma classe de forma
diferenciada. Quando instanciamos uma classe, todos os seus atributos so inicializados para valores pa-
dro. Valores numricos so inicializados para zero, o bool inicializado para false e atributos que guardam
referncias so inicializados para a referncia vazia (valor null do C).
Ento, no exemplo, quando depositamos reais na conta recm-criada, estamos somando no saldo
inicial da conta, que zero, e depois guardando o resultado de volta no saldo da conta.
Podemos mudar o valor padro de um determinado atributo colocando um valor inicial em sua declarao.
Para inicializarmos a conta comsaldo inicial de reais ao invs de zero, podemos utilizar o seguinte cdigo:
class Conta
{
public double saldo = 100.0;
// outros atributos e mtodos da classe
}
Agora toda conta criada j comear com um saldo inicial de ..
. Mn:s cmvxvmvto: TnnNsvvnv
Agora vamos tentar implementar a operao de transferncia de dinheiro entre duas contas. Dentro da classe
Conta criaremos mais um mtodo chamado Transfere, esse mtodo receber o valor da transferncia e as
contas que participaro da operao:
Captulo - Classes e objetos - Valor padro dos atributos da classe - Pgina
Material do Treinamento C e Orientao a Objetos
public void Transfere(double valor, Conta origem, Conta destino)
{
// implementao da transferncia
}
Mas ser que realmente precisamos receber as duas contas como argumento do mtodo Transfere? Vamos
ver como esse mtodo ser utilizado dentro do cdigo do formulrio:
Conta victor = new Conta();
// inicializao da conta
victor.saldo = 1000;
Conta guilherme = new Conta();
// inicializao da conta
// Agora vamos transferir o dinheiro da conta do victor para a do guilherme
victor.Transfere(10.0, victor, guilherme);
Repare que no uso do mtodo estamos repetindo duas vezes a varivel victor, porm isso no necessrio.
Podemos utilizar o this para acessar a conta de origem dentro do mtodo, ento na verdade o mtodo
Transfere precisa receber apenas a conta de destino:
public void Transfere(double valor, Conta destino)
{
// implementao da transferncia
}
Antes de tirarmos dinheiro da conta de origem (this), precisamos verifcar se ela tem saldo sufciente, so-
mente nesse caso queremos sacar o dinheiro da conta de origem e depositar na conta de destino:
public void Transfere(double valor, Conta destino)
{
if(this.saldo >= valor)
{
this.saldo -= valor;
destino.saldo += valor;
}
}
Mas esse comportamento de verifcar se a conta tem saldo sufciente antes de realizar o saque o compor-
tamento do mtodo Saca que foi implementado anteriormente, alm disso, somar um valor no saldo a
operao Deposita da conta. Portanto, podemos utilizar os mtodos Saca e Deposita existentes para imple-
mentar o Transfere:
Captulo - Classes e objetos - Mais um exemplo: Transfere - Pgina
Material do Treinamento C e Orientao a Objetos
public void Transfere(double valor, Conta destino)
{
if(this.Saca(valor))
{
destino.Deposita(valor);
}
}
. CoNvvNXo ov Nomvs
Quando criamos uma classe, importante lembrarmos que seu cdigo ser lido por outros desenvolvedores
da equipe e, por isso, recomendvel seguir padres de nomenclatura.
Quando criamos uma classe, a recomendao utilizar o Pascal Casing para nomear a classe:
Se o nome da classe composto por uma nica palavra, colocamos a primeira letra dessa palavra em
maiscula (conta se torna Conta);
Se o nome composto por diversas palavras, juntamos todas as palavras colocando a primeira letra de
cada palavra em maiscula (seguro de vida se torna SeguroDeVida).
No caso do nome de mtodos, a conveno tambm utilizar o Pascal Casing (Saca e Deposita, por exemplo).
Para argumentos de mtodos, a recomendao utilizar o Pascal Casing porm com a primeira letra em
minscula (valorDoSaque, por exemplo), uma conveno chamada Camel Casing.
Voc pode encontrar as recomendaes da Microsof nesse link:
http://msdn.microsoft.com/en-us/library/ms229040(v=vs.110).aspx
. Exvncc:os
) O que uma classe tem?
S os atributos de uma entidade do sistema;
S atributos ou s mtodos de uma entidade do sistema;
S os mtodos de uma entidade do sistema;
Atributos e mtodos de uma entidade do sistema.
) Vamos criar a classe Conta dentro do projeto inicial utilizando o Visual Studio.
No Visual Studio clique com o boto direito no nome do projeto e selecione a opo Add > Class...
Captulo - Classes e objetos - Conveno de nomes - Pgina
Material do Treinamento C e Orientao a Objetos
Dentro da janela aberta pelo Visual Studio, precisamos defnir qual o nome da classe que queremos
criar. Escolha o nome Conta:
Depois de colocar o nome da classe, clique no boto Add. Com isso, o Visual Studio criar um novo
arquivo dentro do Projeto, o Conta.cs. Todo o cdigo da classe Conta fcar dentro desse arquivo:
class Conta
{
// O cdigo da classe fica aqui dentro!
}
Agora declare os seguintes atributos dentro da Conta: saldo (double), titular (string) e numero (int).
) Qual dos comandos a seguir instancia uma nova Conta?
Conta conta = Conta();
Captulo - Classes e objetos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Conta conta = new Conta();
Conta conta = Conta.new();
) Levando em considerao o cdigo:
Conta c = new Conta();
c.saldo = 1000.0;
Qual das linhas a seguir adiciona reais nesse saldo?
saldo += ;
c.saldo += ;
Conta c.saldo += ;
Conta.saldo += ;
) Agora vamos testar a classe Conta que acabamos de criar. Coloque um novo boto no formulrio da
aplicao. D um duplo clique nesse boto para defnirmos qual ser o cdigo executado no clique do
boto.
private void button1_Click(object sender, EventArgs e)
{
// ao do boto aqui.
}
Dentro do cdigo desse boto, instancie uma nova Conta e tente fazer alguns testes preenchendo e mos-
trando seus atributos atravs do MessageBox.Show. Por exemplo:
private void button1_Click(object sender, EventArgs e)
{
Conta contaVictor = new Conta();
contaVictor.titular = "victor";
contaVictor.numero = 1;
contaVictor.saldo = 100.0;
MessageBox.Show(contaVictor.titular);
}
Tente fazer testes com diversas contas e veja que cada instncia de conta possui seus prprios atributos.
) Agora vamos implementar mtodos na classe Conta. Comearemos pelo mtodo Deposita, esse mtodo
no devolve nada e deve receber um argumento do tipo double que o valor que ser depositado na
Conta. A sua classe deve fcar parecida com a que segue:
// dentro do arquivo Conta.cs
class Conta
Captulo - Classes e objetos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
{
// declarao dos atributos
public void Deposita(double valor)
{
// o que colocar aqui na implementao?
}
}
Depois de implementar o mtodo Deposita, implemente tambm o mtodo Saca. Ele tambm no de-
volve valor algum e recebe um double que o valor que ser sacado da conta.
) Agora vamos testar os mtodos que acabamos de criar. Na ao do boto que utilizamos para testar a
conta, vamos manipular o saldo utilizando os mtodos Deposita e Saca:
private void button1_Click(object sender, EventArgs e)
{
Conta contaVictor = new Conta();
contaVictor.titular = "victor";
contaVictor.numero = 1;
contaVictor.Deposita(100);
MessageBox.Show("Saldo: " + contaVictor.saldo);
contaVictor.Saca(50.0);
MessageBox.Show("Saldo: " + contaVictor.saldo);
}
Tente fazer depsitos e saques em vrias instncias diferentes de Conta, repare que dentro dos mtodos a
varivel this possui o valor da referncia em que o mtodo foi invocado.
) Qual a sada do cdigo a seguir:
Conta mauricio = new Conta();
mauricio.saldo = 2000.0;
Conta guilherme = new Conta();
guilherme.saldo = 5000.0;
mauricio.saldo -= 200.0;
guilherme.saldo += 200.0;
MessageBox.Show("mauricio = " + mauricio.saldo);
MessageBox.Show("guilherme = " + guilherme.saldo);
mauricio = . e guilherme = .
mauricio = . e guilherme = .
mauricio = . e guilherme = .
Captulo - Classes e objetos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
mauricio = . e guilherme = .
) Qual a sada do cdigo a seguir?
Conta mauricio = new Conta();
mauricio.numero = 1;
mauricio.titular = "Mauricio";
mauricio.saldo = 100.0;
Conta mauricio2 = new Conta();
mauricio2.numero = 1;
mauricio2.titular = "Mauricio";
mauricio2.saldo = 100.0;
if (mauricio == mauricio2)
{
MessageBox.Show("As contas so iguais");
}
else
{
MessageBox.Show("As contas so diferentes");
}
As contas so iguais
As contas so diferentes
No mostrado nenhuma mensagem
) Qual a sada do cdigo a seguir:
Conta mauricio = new Conta();
mauricio.saldo = 2000.0;
Conta copia = mauricio;
copia.saldo = 3000.0;
MessageBox.show("mauricio = " + mauricio.saldo);
MessageBox.show("copia = " + copia.saldo);
mauricio = . e copia = .
mauricio = . e copia = .
mauricio = . e copia = .
mauricio = . e copia = .
) (Opcional) Implemente o mtodo Transfere que recebe o valor da transferncia e a conta de destino.
Faa com que ele reutilize as implementaes dos mtodos Saca e Deposita.
Captulo - Classes e objetos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) (Opcional) Vamos adicionar uma validao no mtodo Saca da Conta. Modifque o mtodo Saca para que
ele no realize o saque caso o saldo atual da conta seja menor do que o valor recebido como argumento.
) (Opcional) Modifque o mtodo Saca comvalidao para que ele devolva o valor true caso o saque tenha
sido realizado com sucesso e false caso contrrio. Depois modifque o cdigo do boto de teste da conta
para que ele utilize o valor devolvido pelo mtodo Saca para mostrar uma mensagem para o usurio.
Caso o saque seja bem sucedido, queremos mostrar a mensagem Saque realizado com sucesso, se no,
mostraremos Saldo insufciente
) (Opcional) Agora altere o mtodo Saca da classe Conta. Limite o valor do saque para R , caso o
cliente seja menor de idade.
Lembre-se que ainda necessrio validar se o valor a ser sacado menor ou igual ao saldo atual do cliente
e maior do que R ,.
. Comvos:Xo ov ctnssvs
Quando abrimos uma conta no banco, temos que fornecer uma srie de informaes: nome, CPF, RG e
endereo.
Vimos que quando queremos armazenar informaes em uma classe, devemos criar atributos. Mas em qual
classe colocar esses novos atributos? Claramente essas informaes no pertencema uma Conta. Esses dados
pertencem ao titular da conta, ou seja, essas informaes pertencem ao cliente do banco.
Ento devemos armazen-las em uma classe Cliente.
class Cliente
{
public string nome;
public string cpf;
public string rg;
public string endereco;
}
Sabemos tambmque toda conta est associada a umcliente, ou seja, a conta guarda uma referncia ao cliente
associado.
class Conta
{
// outros atributos da Conta
public Cliente titular;
// comportamentos da conta
}
Captulo - Classes e objetos - Composio de classes - Pgina
Material do Treinamento C e Orientao a Objetos
Agora, quando vamos criar uma conta, podemos tambm colocar seu titular.
Cliente victor = new Cliente();
victor.nome = "victor";
Conta umaConta = new Conta();
umaConta.titular = victor;
Vimos tambm que o atributo titular guarda uma referncia(seta) para uma instncia de Cliente (objeto
na memria). Logo, a atribuio umaConta.titular = victor est copiando a referncia da varivel victor
para o atributo titular.
Podemos modifcar os atributos do Cliente atravs da referncia guardada no atributo titular da Conta.
Cliente victor = new Cliente();
victor.nome = "victor";
Conta umaConta = new Conta();
umaConta.titular = victor;
umaConta.titular.rg = "12345678-9";
// Mostra o nome victor
MessageBox.Show(umaConta.titular.nome);
// Mostra o texto 12345678-9
MessageBox.Show(victor.rg);
. Exvncc:os
) Crie a classe Cliente contendo os atributos nome (string), rg (string), cpf (string) e endereco (string).
Modifque a classe Conta e faa com que seu atributo titular seja do tipo Cliente ao invs de string.
Tome cuidado. Aps essa modifcao no poderemos atribuir o nome do cliente diretamente ao atributo
titular da Conta. Para defnir o nome do titular, precisaremos de um cdigo parecido com o que segue:
Conta conta = new Conta();
Cliente cliente = new Cliente();
conta.titular = cliente;
conta.titular.nome = "Victor";
) Qual a sada que ser impressa ao executar o seguinte trecho de cdigo?
Conta umaConta = new Conta();
Cliente guilherme = new Cliente();
Captulo - Classes e objetos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
guilherme.nome = "Guilherme Silveira";
umaConta.titular = guilherme;
MessageBox.Show(umaConta.titular.nome);
Guilherme Silveira
Ser mostrado uma caixa de mensagem sem nenhuma mensagem
O cdigo no compila
) Qual a sada que ser impressa ao executar o seguinte trecho de cdigo?
Conta umaConta = new Conta();
Cliente guilherme = new Cliente();
guilherme.rg = "12345678-9";
umaConta.titular = guilherme;
umaConta.titular.rg = "98765432-1";
MessageBox.Show(guilherme.rg);
-
-
rg
No ser impresso nada
) (Opcional) Crie mais umatributo na classe Cliente que guarda a idade da pessoa. No nosso caso, a idade
um nmero inteiro.
Tambm crie um comportamento (mtodo) com o nome EhMaiorDeIdade na classe Cliente que no
recebe nenhumargumento e retorna umbooleano indicando se o cliente maior de idade ouno. Quando
uma pessoa maior de idade no Brasil?
Captulo - Classes e objetos - Exerccios - Pgina
C
Encapsulamento e Modifcadores de Acesso
Nesse momento, nossa classe Conta possui um numero, saldo e cliente titular, alm de comportamentos
que permitem sacar e depositar:
class Conta
{
public int numero;
public double saldo;
public Cliente titular;
public void Saca(double valor) {
this.saldo -= valor;
}
public void Deposita(double valor) {
this.saldo += valor;
}
}
Se desejamos efetuar um saque ou um depsito em uma Conta qualquer, fazemos:
conta.Saca(100.0);
conta.Deposita(250.0);
Mas o que acontece se um membro da equipe faz:
conta.saldo -= 100.0;
Material do Treinamento C e Orientao a Objetos
Nada nos impede de acessar os atributos diretamente. Em trs partes distintas do nosso sofware temos tal
cdigo:
// em um arquivo
conta.saldo -= 100.0;
// em outro arquivo
conta.saldo -= 250.0;
// em outro arquivo
conta.saldo -= 371.0;
Agora imagine que o banco mude a regra de saque: agora a cada saque realizado, o banco cobrar . centa-
vos. Ou seja, se o usurio sacar . reais, necessrio tirar de sua conta . reais. Temos que alterar todos
os pontos de nossa aplicao que acessam esse atributo! Mas nossa base de cdigo pode ser muito grande e
muito comum esquecermos onde e quem est acessando esse atributo, deixando bugs toda vez que esque-
cemos de alterar algum lugar. Se tivermos essa linha espalhada vezes em nosso sistema, precisaremos
encontrar todas essas linhas e fazer a alterao. Muito complicado e custoso!
O que aconteceria ao usarmos o mtodo Saca():
// em um arquivo
conta.Saca(100.0);
// em outro arquivo
conta.Saca(250.0);
// em outro arquivo
conta.Saca(371.0);
Como refetiramos a alterao na regra do saque de tirar centavos? Precisamos alterar apenas uma vez o
mtodo Saca(), ao invs de alterar todas as linhas que acessam o atributo diretamente!
. ENcnvsctnmvN1o
Quando liberamos o acesso aos atributos da classe Conta, estamos permitindo que qualquer programador
faa a sua prpria implementao no segura da lgica de saque da forma que quiser. Se a modifcao do
atributo fcasse restrita classe que o declara, todos que quisessem sacar ou depositar dinheiro na conta te-
riamde faz-lo atravs de mtodos da classe. Nesse caso, se a regra de saque mudar no futuro, modifcaremos
apenas o mtodo Saca.
Na orientao a objetos, esconder os detalhes de implementao de uma classe um conceito conhecido
como encapsulamento. Como os detalhes de implementao da classe esto escondidos, todo o acesso deve
Captulo - Encapsulamento e Modifcadores de Acesso - Encapsulamento - Pgina
Material do Treinamento C e Orientao a Objetos
ser feito atravs de seus mtodos pblicos. No permitimos aos outros saber COMO a classe faz o trabalho
dela, mostrando apenas O QU ela faz.
Veja a linha conta.Saca(100.0);. Sabemos o qu esse mtodo faz pelo seu nome. Mas como ele faz o
trabalho dele s saberemos se entrarmos dentro de sua implementao. Portanto, o comportamento est
encapsulado nesse mtodo.
Mas ainda no resolvemos o problema de evitar que programadores faam uso diretamente do atributo.
Qualquer um ainda pode executar o cdigo abaixo:
conta.saldo -= 371.0;
Para isso, precisamos esconder o atributo. Queremos deix-lo privado para que somente a prpria classe
Conta possa utiliz-lo. Nesse caso queremos modifcar oacesso ao atributo para que ele seja privado, private:
class Conta
{
// outros atributos aqui
private double saldo;
public void Saca(double valor) {
this.saldo -= valor;
}
public void Deposita(double valor) {
this.saldo += valor;
}
}
Atributos e mtodos private so acessados apenas pela prpria classe. Ou seja, o mtodo Saca(), por exem-
plo, consegue fazer alteraes nele. Mas outras classes no conseguem acess-lo diretamente! O compilador
no permite!
Os atributos de uma classe so detalhes de implementao, portanto marcaremos todos os atributos da conta
com a palavra private:
class Conta
{
private int numero;
private double saldo;
private Cliente titular;
public void Saca(double valor) {
this.saldo -= valor;
}
Captulo - Encapsulamento e Modifcadores de Acesso - Encapsulamento - Pgina
Material do Treinamento C e Orientao a Objetos
public void Deposita(double valor) {
this.saldo += valor;
}
}
timo. Agora o programador forado a passar pelos mtodos para conseguir manipular o saldo. Se ten-
tarmos, por exemplo, escrever no saldo da Conta a partir do cdigo de um formulrio, teremos um erro de
compilao:
Conta c = new Conta();
// A linha abaixo gera um erro de compilao
c.saldo = 100.0;
Mas agora temos outro problema. Se quisermos exibir o saldo no conseguiremos. Oprivate bloqueia tanto
a escrita, quanto a leitura!
. CoN1notnNoo o ncvsso comvnovvn1:vs
Vimos que podemos proibir o acesso externo a umatributo utilizando o private do C, mas o private tambm
bloqueia a leitura do atributo, logo para recuperarmos seu valor, precisamos de um novo mtodo dentro da
classe que nos devolver o valor atual do atributo:
class Conta
{
private double saldo;
private int numero;
// outros atributos e mtodos da conta
public double PegaSaldo()
{
return this.saldo;
}
}
Agora para mostrarmos o saldo para o usurio, utilizaramos o seguinte cdigo:
Conta conta = new Conta();
// inicializa a conta
MessageBox.Show("saldo: " + conta.PegaSaldo());
Captulo - Encapsulamento e Modifcadores de Acesso - Controlando o acesso com properties - Pgina
Material do Treinamento C e Orientao a Objetos
Alm disso, a conta precisa de um nmero, mas como ele foi declarado como private, no podemos acess-
lo diretamente. Precisaremos de um novo mtodo para fazer esse trabalho:
class Conta
{
private int numero;
// outros atributos e mtodos da conta
public void ColocaNumero(int numero)
{
this.numero = numero;
}
}
Para colocarmos o nmero na conta, teramos que executar esse cdigo:
Conta conta = new Conta();
conta.ColocaNumero(1100);
//utiliza a conta no cdigo
Veja que com isso ns conseguimos controlar todo o acesso a classe Conta, mas para escrevermos ou lermos
o valor de um atributo precisamos utilizar os mtodos. O ideal seria utilizarmos uma sintaxe parecida com
a de acesso a atributos, porm com o controle que o mtodo nos oferece. Para resolver esse problema, o C
nos oferece as properties (propriedades).
Adeclarao de uma propriedade parecida coma declarao de umatributo, pormprecisamos falar o que
deve ser feito na leitura (get) e na escrita (set) da propriedade
class Conta
{
private int numero;
public int Numero
{
get
{
// cdigo para ler a propriedade
}
set
{
Captulo - Encapsulamento e Modifcadores de Acesso - Controlando o acesso com properties - Pgina
Material do Treinamento C e Orientao a Objetos
// cdigo para escrever na propriedade
}
}
}
Na leitura da propriedade, queremos devolver o valor do atributo numero da Conta:
class Conta
{
private int numero;
public int Numero
{
get
{
return this.numero;
}
}
}
Com isso, podemos ler a propriedade Numero com o seguinte cdigo:
Conta c = new Conta();
MessageBox.Show("numero: " + c.Numero);
Veja que o acesso fcou igual ao acesso de atributos, porm quando tentamos ler o valor de uma propriedade
estamos na verdade executando um bloco de cdigo (get da propriedade) da classe Conta. Para defnirmos
o nmero da conta, utilizaremos o cdigo:
Conta c = new Conta();
c.Numero = 1;
Quando tentamos escrever em uma propriedade, o C utiliza o bloco set para guardar seu valor. Dentro
do bloco set, o valor que foi atribudo propriedade fca dentro de uma varivel chamada value, ento
podemos implementar o set da seguinte forma:
class Conta
{
private int numero;
public int Numero
{
// declarao do get
Captulo - Encapsulamento e Modifcadores de Acesso - Controlando o acesso com properties - Pgina
Material do Treinamento C e Orientao a Objetos
set
{
this.numero = value;
}
}
}
Podemos tambm declarar uma propriedade que tem apenas o get, sem o set. Nesse caso, estamos decla-
rando uma propriedade que pode ser lida mas no pode ser escrita. Comas properties conseguimos controlar
completamente o acesso aos atributos da classe utilizando a sintaxe de acesso aos atributos.
. S:mvt:v:cnNoo n ovctnnnXo ov vnovn:vonovs com Ac1o-
ImvtvmvN1vo Pnovvn1:vs
Utilizando as properties, conseguimos controlar o acesso s informaes da classe, porm, como vimos,
declarar uma property bem trabalhoso. Precisamos de um atributo para guardar seu valor, alm disso,
precisamos declarar o get e o set.
Para facilitar a declarao das properties, a partir do C ., temos as propriedades que so implemen-
tadas automaticamente pelo compilador, as auto-implemented properties. Para declararmos uma auto-
implemented property para expor o nmero da conta, utilizamos o seguinte cdigo:
class Conta
{
public int Numero { get; set; }
}
Esse cdigo faz com que o compilador declare um atributo do tipo int (cujo nome s conhecido pelo
compilador) e gere o cdigo para a propriedade Numero com um get e um set que leem e escrevem no
atributo declarado. Repare que ao utilizarmos as auto-implemented properties, s podemos acessar o valor
do atributo declarado atravs da propriedade.
Toda vez que declaramos um auto-implemented property, precisamos sempre declarar um get e um set
para a propriedade, porm podemos controlar a visibilidade tanto do get quanto do set. Por exemplo, no
caso do saldo, queremos permitir que qualquer um leia o saldo da conta, porm apenas a prpria conta pode
alter-lo. Nesse caso, utilizamos o seguinte cdigo:
class Conta
{
// outras propriedades
// get pblico e pode ser acessado por qualquer classe
Captulo - Encapsulamento e Modifcadores de Acesso - Simplifcando a declarao de propriedades com Auto-Implemented
Properties - Pgina
Material do Treinamento C e Orientao a Objetos
// set privado e por isso s pode ser usado pela conta.
public double Saldo { get; private set; }
// resto do cdigo da classe.
}
Agora vamos ver um cdigo que tenta ler e escrever nas propriedades que declaramos:
Conta c = new Conta();
c.Numero = 1; // funciona pois o set do Numero pblico
MessageBox.Show("numero: " + c.Numero); // funciona pois o get do Numero pblico
c.Saldo = 100.0; // set do Saldo privado, ento temos um erro
MessageBox.Show("saldo " + c.Saldo); // funciona pois o get do Saldo pblico.
Veja que tanto declarando properties explicitamente quanto utilizando as auto-implemented properties, te-
mos o controle total sobre quais informaes sero expostas pela classe.
Ento devemos utilizar properties toda vez que queremos expor alguma informao da classe. Nunca deve-
mos expor atributos da classe (utilizando o public), pois nunca queremos expor os detalhes de implemen-
tao da classe.
. CoNvvNXo ov Nomv vnnn vnovvn1v
Aconveno de nomes defnida para properties do C a mesma conveno de nomes utilizada para classes,
ou seja, utilizando o Pascal Casing (Todas as palavras do nome so concatenadas e cada palavra tem a inicial
maiscula, por exemplo: numero do banco => NumeroDoBanco)
. Exvncc:os
) Qual o comportamento do atributo abaixo:
public int Numero { get; private set; }
O nmero pode ser lido, mas no pode ser alterado por outras classes.
O nmero no pode ser lido, mas pode ser alterado por outras classes.
O nmero no pode nem ser lido nem ser alterado por outras classes.
O nmero pode ser lido e alterado por outras classes.
) Sobre o cdigo abaixo vlido afrmar que...
Captulo - Encapsulamento e Modifcadores de Acesso - Conveno de nome para property - Pgina
Material do Treinamento C e Orientao a Objetos
Conta c = new Conta();
double valorADepositar = 200.0;
c.Saldo += valorADepositar;
A operao de depsito foi implementada corretamente.
A operao de depsito no est encapsulada, podendo gerar problemas futuros de manuteno.
A operao de depsito no est encapsulada, facilitando a manuteno futura do cdigo.
) O que encapsulamento?
deixar bem claro para todos COMO a classe faz o trabalho dela.
a utilizao de Properties em qualquer uma de suas variaes.
manipular e alterar atributos diretamente, sem passar por um mtodo especfco.
esconder COMO a classe/mtodo faz sua tarefa. Caso a regra mude, temos que alterar apenas um
ponto do cdigo.
) Qual o problema do atributo abaixo:
public double Saldo { get; set; }
Nenhum. Ele est encapsulado, afnal usamos Properties.
Ao invs de public, deveramos usar private.
Oatributo Saldo pode ser manipulado por outras classes. Isso vai contra a regra do encapsulamento.
De nada adianta criar Properties e permitir que todos os atributos sejam modifcados pelas outras
classes.
) Transforme os atributos da classe Conta em propriedades. Permita que o saldo da conta seja lido, porm
no seja alterado fora da classe, altere tambm o cdigo das classes que utilizam a conta para que elas
acessem as propriedades ao invs dos atributos diretamente.
. Pnnn snnvn mn:s: V:s:n:t:onov IN1vnNnt
Quando escrevemos uma aplicao grande, muitas vezes utilizamos bibliotecas que so desenvolvidas por
outras pessoas, as DLLs (Dynamic Link Library). E muitas vezes a aplicao precisa compartilhar classes
com a dll importada no cdigo.
Quando declaramos uma classe no C, por padro ela s pode ser vista dentro do prprio projeto (visvel
apenas no assembly que a declarou), esse um nvel de visibilidade conhecido como internal. Quando que-
remos trabalhar combibliotecas externas ao projeto, nossas classes precisamser declaradas coma visibilidade
public:
Captulo - Encapsulamento e Modifcadores de Acesso - Para saber mais: Visibilidade Internal - Pgina
Material do Treinamento C e Orientao a Objetos
public class AtualizadorDeContas
{
// Implementao da classe
}
Comessa modifcao, a classe AtualizadorDeContas visvel inclusive fora do assembly que a declarou, ou
seja, podemos utiliz-la em qualquer ponto do cdigo.
Dentro dessa classe AtualizadorDeContas, vamos declarar um mtodo chamado Atualiza que recebe uma
Conta como argumento.
public class AtualizadorDeContas
{
public void Atualiza(Conta conta)
{
}
}
Como esse um mtodo pblico dentro de uma classe pblica, ele pode ser utilizado em qualquer ponto do
cdigo, inclusive em outros assemblies. Porm se a classe Conta for uma classe com visibilidade internal,
teremos um mtodo que pode ser visto em todos os pontos do cdigo, que recebe um argumento visvel
apenas dentro do assembly que o declarou, ou seja, temos uma inconsistncia nas visibilidades.
Quando o compilador do C detecta uma inconsistncia de visibilidade, ele gera um erro de compilao avi-
sando quais so os mtodos e classes que esto inconsistentes. Para corrigirmos o problema de inconsistncia
do exemplo do AtualizadorDeContas, precisamos declarar a classe Conta como public:
public class Conta
{
// implementao da classe
}
Oualternativamente, podemos deixar a classe AtualizadorDeContas ouo mtodo Atualiza comvisibilidade
internal:
// internal a visibilidade padro para a classe,
// portanto a palavra internal opcional
internal class AtualizadorDeContas
{
// implementao da classe
}
Captulo - Encapsulamento e Modifcadores de Acesso - Para saber mais: Visibilidade Internal - Pgina
C
Construtores
Com o que vimos nos captulos anteriores, ns precisamos lembrar de colocar o nome aps criarmos um
novo cliente em nosso sistema. Isso pode ser visto no cdigo a seguir:
Cliente guilherme = new Cliente();
guilherme.Nome = "Guilherme";
E se esquecermos de chamar a segunda linha desse cdigo, teremos um cliente sem nome. Mas, ser que faz
sentido existir um cliente sem nome?
Para evitar isso, ao construir nosso objeto temos que obrigar o desenvolvedor a falar qual o nome do Cliente.
Isto , queremos ser capazes de alterar o comportamento da construo do objeto.
Queremos defnir um novo comportamento que dir como ser construdo o objeto. Algo como:
Cliente guilherme = new Cliente("Guilherme Silveira");
Note que esse comportamento que desejamos lembra um comportamento normal, passando argumentos,
mas com a caracterstica especial de ser quem constri um objeto. Esse comportamento recebe o nome de
construtor. E como defni-lo? Similarmente a um comportamento qualquer:
class Cliente
{
// Outros atributos da classe Cliente
public string Nome { get; set; }
public Cliente (string nome)
{
this.Nome = nome;
Material do Treinamento C e Orientao a Objetos
}
}
Vimos que quando criamos um construtor na classe, o C usa o construtor criado para inicializar o objeto,
pormo que acontece quando no temos nenhumconstrutor na classe? Quando uma classe no temnenhum
construtor, o C coloca um construtor padro dentro da classe. Esse construtor no recebe argumentos e
no executa nenhuma ao, ou seja, um construtor que no recebe nenhum argumento e tem o corpo vazio.
. Mt1:vtos coNs1nc1onvs ovN1no on ctnssv
Na seo anterior defnimos um construtor dentro da classe cliente que inicializa a propriedade nome, mas
e se quisssemos inicializar tambm a idade do Cliente durante a construo do objeto? Nesse caso, preci-
saramos de um construtor adicional na classe Cliente:
class Cliente
{
public string Nome { get; set; }
public int Idade { get; set; }
// construtor que s recebe o nome
public Cliente (string nome)
{
this.Nome = nome;
}
// construtor que recebe o nome e a idade
public Cliente (string nome, int idade)
{
this.Nome = nome;
this.Idade = idade;
}
}
Veja que defnimos duas verses diferentes do construtor da classe, uma que recebe apenas a string nome
e outra que recebe string nome e int idade. Quando colocamos diversas verses do construtor dentro de
uma classe, estamos fazendo uma sobrecarga de construtores.
Captulo - Construtores - Mltiplos construtores dentro da classe - Pgina
Material do Treinamento C e Orientao a Objetos
Vnton vnonXo vnnn os vnnXmv1nos
No C, ao invs de fazermos sobrecarga de construtores para podermos passar informaes adi-
cionais na criao do objeto, podemos utilizar os parmetros opcionais com valores padro.
Voc pode ler sobre os parmetros opcionais no blog da caelum: http://blog.caelum.com.br/
parametros-opcionais-e-nomeados-do-c/
. Pnnn snnvn mn:s IN:1:nt:zvn
Vimos que podemos utilizar um construtor para pedir informaes obrigatrias para a classe. Mas, por
exemplo, temos a classe Cliente e apenas seu nome obrigatrio, ento podemos pedir essa informao no
construtor da classe.
Cliente cliente = new Cliente ("Victor Harada");
Mas o cliente tambm possui CPF, RG e idade. Para colocarmos essas informaes no cliente que criamos
precisamos do cdigo:
Cliente cliente = new Cliente ("Victor Harada");
cliente.Cpf = "123.456.789-01";
cliente.Rg = "21.345.987-x";
cliente.Idade = 25;
Veja que em todas as linhas estamos repetindo o nome da varivel que guarda a referncia para o cliente.
Para evitar essa repetio, podemos utilizar os initializers do C. O Initializer um bloco de cdigo que
serve para inicializar as propriedades pblicas do objeto.
Cliente cliente = new Cliente ("Victor Harada")
{
// bloco de inicializao
Cpf = "123.456.789-01",
Rg = "21.345.987-x",
Idade = 25
};
. Exvncc:os
) Ao modelar um sistema de controle de avies em um aeroporto, todos os avies possuem, obrigatoria-
mente, um cdigo e uma empresa, alm disso, opcionalmente, uma cidade de entrada e sada.
Qual soluo parece ser mais fcil de manter?
Captulo - Construtores - Para saber mais Initializer - Pgina
Material do Treinamento C e Orientao a Objetos
Criar um construtor para cdigo e empresa, e quatro propriedades: cdigo, empresa, cidade de
entrada e de sada.
Criar um construtor para cdigo, empresa, entrada e sada e no criar propriedades.
Criar quatro propriedades: cdigo, empresa, cidade de entrada e de sada.
Criar um construtor para cdigo e empresa, e duas propriedades cidade de entrada e de sada.
) Qual das opes a seguir representa um construtor da classe Cliente que recebe o nome e o rg?
class Cliente
{
// Outros atributos da classe Cliente
public string Nome { get; set; }
public string Rg { get; set; }
public Cliente (string nome, string rg)
{
this.Nome = nome;
this.Rg = rg;
}
// Outros mtodos e construtores
}
class Cliente
{
// Outros atributos da classe Cliente
public string Nome { get; set; }
public string Rg { get; set; }
public Cliente (string nome)
{
this.Nome = nome;
this.Rg = rg;
}
// Outros mtodos e construtores
}
class Cliente
{
// Outros atributos da classe Cliente
public string Nome { get; set; }
public string Rg { get; set; }
public void Cliente (string nome, string rg)
{
this.Nome = nome;
this.Rg = rg;
}
Captulo - Construtores - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
// Outros mtodos e construtores
}
class Cliente
{
// Outros atributos da classe Cliente
public string Nome { get; set; }
public string Rg { get; set; }
public int Cliente (string nome, string rg)
{
this.Nome = nome;
this.Rg = rg;
}
// Outros mtodos e construtores
}
) Faa com que o nome possa, opcionalmente, ser passado na construo da classe Cliente.
Captulo - Construtores - Exerccios - Pgina
C
Introduo ao Visual Studio com Windows Form
Agora que j sabemos os conceitos bsicos de Orientao a Objetos, chegou a hora de aprendermos como
ganhar produtividade utilizando o Visual Studio para desenvolver uma interface grfca para o projeto do
banco. Vamos criar um novo projeto utilizando o atalho Ctrl + Shift + N do Visual Studio. Esse atalho
abrir a janela de novo projeto. Nessa janela escolheremos novamente o tipo Windows Form Application.
O nome desse novo projeto ser Banco.
Dentro desse projeto, queremos colocar campos de texto para mostrar as informaes da conta, para isso
utilizaremos um novo componente do Windows form chamado TextBox. Colocaremos trs TextBox dentro
do formulrio.
Para defnir o texto que ser exibido no TextBox, precisaremos de uma varivel que guardar a referncia
para o componente TextBox. Para defnir o nome dessa varivel, devemos clicar com o boto direito no
TextBox e escolher a opo Properties
Material do Treinamento C e Orientao a Objetos
O Visual C colocar a janela Properties em destaque:
Dentro da Properties, procure o campo (Name). O nome que for colocado nesse campo ser o nome da
varivel que conter a referncia para a instncia de TextBox. Vamos, por exemplo, defnir que o nome do
campo ser textoTitular.
Podemos utilizar a referncia para o TextBox para defnir o texto que ser exibido:
textoTitular.Text = "Texto da minha caixa da texto";
Vamos chamar os outros TextBox de textoNumero e textoSaldo. Agora precisamos defnir o cdigo do
formulrio que ser utilizado para preencher as informaes do formulrio.
Captulo - Introduo ao Visual Studio com Windows Form - - Pgina
Material do Treinamento C e Orientao a Objetos
. IN1noocXo vnK1:cn nos n1ntnos oo V:scnt S1co:o
Para fazer com que o formulrio comece preenchido com a informao do titular da conta, precisamos criar
um mtodo no formulrio que ser responsvel por sua inicializao. Podemos criar esse mtodo dando um
duplo clique no formulrio:
private void Form1_Load(object sender, EventArgs e)
{
// carregue os campos de seu formulrio aqui
}
Dentro desse mtodo, queremos preencher as informaes do formulrio com os dados de uma conta que
ser instanciada. Vamos inicialmente instanciar a conta que ser gerenciada pela aplicao:
private void Form1_Load(object sender, EventArgs e)
{
Conta c = new Conta();
}
Pormesse cdigo gera umerro de compilao pois nesse projeto ainda no criamos a classe Conta. Faremos
o Visual Studio gerar a declarao dessa classe. Coloque o cursor do teclado sobre o nome da classe Conta e
aperte o atalho Ctrl + ., o Visual Studio dar a opo Generate class for 'Conta':
No precisamos nos preocupar em criar cada classe do projeto manualmente, podemos deixar o prprio
Visual Studio fazer o trabalho! Mude a visibilidade da classe gerada para public.
// Arquivo Conta.cs
public class Conta
{
}
Agora vamos voltar ao cdigo do formulrio e inicializar a propriedade Numero da conta da varivel c:
Captulo - Introduo ao Visual Studio com Windows Form - Introduo prtica aos atalhos do Visual Studio - Pgina
Material do Treinamento C e Orientao a Objetos
private void Form1_Load(object sender, EventArgs e)
{
Conta c = new Conta();
c.Numero = 1;
}
Ao adicionarmos essa linha, teremos novamente um erro de compilao, pois a conta ainda no possui a
propriedade Numero. Coloque o cursor sobre a propriedade Numero e aperte novamente o Ctrl + .. Dessa
vez o visual studio mostrar a opo Generate property stub for Numero in Banco.Conta, escolha essa
opo.
Com isso a propriedade ser criada automaticamente dentro da classe Conta.
public class Conta
{
public int Numero { get; set; }
}
Vamos tambm declarar a propriedade Saldo dentro da Conta, para isso utilizaremos um novo atalho do
visual studio. Abaixo da propriedade Numero que foi declarada anteriormente, digite prop e depois aperte a
tecla tab duas vezes:
public class Conta
{
public int Numero { get; set; }
prop + <tab> + <tab>
}
Esse o atalho para declarar uma nova propriedade pblica dentro do cdigo.
public class Conta
{
public int Numero { get; set; }
public int MyProperty { get; set; }
}
Captulo - Introduo ao Visual Studio com Windows Form - Introduo prtica aos atalhos do Visual Studio - Pgina
Material do Treinamento C e Orientao a Objetos
Veja que, na propriedade criada pelo visual studio, o tipo da propriedade e seu nome esto marcados com
uma cor de fundo diferente porque ainda no falamos qual ser o tipo e o nome da nova propriedade. Como
estamos criando a propriedade para o saldo da conta, colocaremos o tipo double. Depois de defnir o tipo
da propriedade, aperte a tecla tab, isso mudar o foco do editor para o nome da propriedade. Digite o nome
Saldo:
public class Conta
{
public int Numero { get; set; }
public double Saldo { get; set; }
}
Mas apenas a conta pode alterar o Saldo, as outras classes devem conseguir fazer apenas a leitura. Por isso
marcaremos o set da propriedade com a palavra private.
public double Saldo { get; private set; }
Da mesma forma que criamos a propriedade como atalho prop + <tab> + <tab> , tambmpodemos criar
um construtor para a classe utilizando o ctor + <tab> + <tab>.
Para terminar a declarao das propriedades da conta, vamos colocar o Titular. Volte classe do formulrio
principal da aplicao. Dentro do cdigo da inicializao formulrio, instancie umnovo cliente passando seu
nome como argumento do construtor:
private void Form1_Load(object sender, EventArgs e)
{
Conta c = new Conta();
c.Numero = 1;
Cliente cliente = new Cliente("victor");
}
Isso novamente far o Visual Studio apontar erros de compilao no cdigo e, novamente, utilizaremos o
Ctrl + . para corrigir esse erro. Coloque o cursor do teclado sobre o tipo cliente, aperte Ctrl + . e seleci-
one a opo Generate class for 'Cliente'. Modifque a visibilidade da classe criada para public e volte
novamente classe do formulrio.
O cdigo do formulrio ainda possui o erro de compilao porque a classe Cliente que acabamos de criar
no possui um construtor que recebe uma string como argumento. Ento vamos novamente colocar o
cursor do teclado sobre o erro de compilao, apertar Ctrl + . e escolher a opo Generate constructor
stub in 'Banco.Cliente'.
Captulo - Introduo ao Visual Studio com Windows Form - Introduo prtica aos atalhos do Visual Studio - Pgina
Material do Treinamento C e Orientao a Objetos
Com isso criamos automaticamente o construtor dentro da classe Cliente.
public class Cliente
{
private string p;
public Cliente(string p)
{
this.p = p;
}
}
Veja que no cdigo do construtor o valor do argumento passado guardado dentro de um atributo que
foi declarado automaticamente, porm queremos guardar esse valor dentro de uma propriedade chamada
Nome do Cliente. Apague o atributo que foi criado automaticamente pelo visual studio e depois modifque
o cdigo do construtor para:
public class Cliente
{
public Cliente(string p)
{
this.Nome = p;
}
}
Quando modifcarmos o cdigo, o Visual Studio automaticamente mostrar umerro de compilao na classe
Cliente porque a propriedade Nome ainda no foi declarada, ento vamos cri-la. Dentro do cdigo do cons-
trutor, coloque seucursor sobre a palavra Nome e depois aperte Ctrl + ., escolha a opo Generate property
stub for 'Nome'in 'Banco.Cliente'. Com isso, o Visual Studio criar automaticamente a propriedade
Nome dentro da classe Cliente:
public class Cliente
{
public Cliente(string p)
{
this.Nome = p;
}
Captulo - Introduo ao Visual Studio com Windows Form - Introduo prtica aos atalhos do Visual Studio - Pgina
Material do Treinamento C e Orientao a Objetos
public string Nome { get; set; }
}
Agora voltando ao cdigo do formulrio, precisamos guardar o cliente que foi criado na propriedade Titular
da Conta:
private void Form1_Load(object sender, EventArgs e)
{
Conta c = new Conta();
c.Numero = 1;
Cliente cliente = new Cliente("victor");
c.Titular = cliente;
}
Com esse cdigo temos novamente um erro de compilao, ento utilizaremos o Ctrl + . para criar a
propriedade Titular dentro da Conta.
. A ctnssv CoNvvn1
Depois de criarmos a classe Conta, precisamos mostrar seus dados nos TextBoxs que foram adicionados.
Como vimos, para colocar o texto que ser mostrado em um TextBox, precisamos apenas escrever na pro-
priedade Text do objeto. Ento para mostrarmos o nome do titular, precisamos do seguinte cdigo:
private void Form1_Load(object sender, EventArgs e)
{
Conta c = new Conta();
// inicializa a Conta c
textoTitular.Text = c.Titular.Nome;
}
No caso do nmero da conta, precisamos convert-lo para uma string antes de escrev-lo na propriedade
Text.
Quando queremos fazer converses entre os tipos bsicos do C, utilizamos uma classe chamada Convert do
C. Dentrodessa classe, podemos utilizar omtodoToString para converter umtipo primitivoda linguagem
para uma string. O cdigo para mostrar as propriedades Numero e Saldo da conta fca da seguinte forma:
textoNumero.Text = Convert.ToString(c.Numero);
textoSaldo.Text = Convert.ToString(c.Saldo);
Captulo - Introduo ao Visual Studio com Windows Form - A classe Convert - Pgina
Material do Treinamento C e Orientao a Objetos
. Ovvnnovs Nn coN1n: snqcv v ovvos:1o
Agora vamos implementar botes no formulrio que manipulam a conta que est sendo exibida. Vamos
inicialmente implementar a operao de depsito. Para isso, arraste para dentro do formulrio uma nova
caixa de texto e faa com que o nome da varivel dessa caixa seja textoValor. Alm dessa caixa, arraste um
novo boto para o formulrio. Quando o usurio clicar nesse boto, o cdigo deve ler o valor digitado na
caixa textoValor e convert-lo para um double que ser passado para o mtodo Deposita.
D umduplo clique no boto para associar uma ao emseu evento de clique. Dentro da ao do boto, para
pegarmos o texto que foi digitado no textoValor, precisamos apenas ler a sua propriedade Text:
private void button1_Click(object sender, EventArgs e)
{
string valorDigitado = textoValor.Text;
}
Agora precisamos fazer a converso do valorDigitado para o tipo double do C. Para realizar essa conver-
so, utilizaremos o mtodo ToDouble da classe Convert:
private void button1_Click(object sender, EventArgs e)
{
string valorDigitado = textoValor.Text;
double valorOperacao = Convert.ToDouble(valorDigitado);
}
E agora que temos o valor da operao no tipo correto, vamos utilizar o mtodo Deposita da classe Conta:
private void button1_Click(object sender, EventArgs e)
{
string valorDigitado = textoValor.Text;
double valorOperacao = Convert.ToString(valorDigitado);
c.Deposita(valorOperacao);
}
Mas a ao desse boto no pode acessar uma varivel que foi declarada dentro do mtodo Form1_Load. Para
que a mesma conta possa ser utilizada em diferentes mtodos do formulrio, ela precisa ser declarada como
um atributo da classe do formulrio que foi gerada pelo Visual Studio:
public class Form1 : Form
{
private Conta c;
// resto da classe do formulrio.
}
Captulo - Introduo ao Visual Studio com Windows Form - Operaes na conta: saque e depsito - Pgina
Material do Treinamento C e Orientao a Objetos
Dentro do Form1_Load, guardaremos a conta criada dentro do novo atributo do formulrio:
private void Form1_Load(object sender, EventArgs e)
{
// Cria uma nova conta e guarda sua referncia no atributo do formulrio
this.c = new Conta();
// inicializa e mostra a conta no formulrio
}
Como a conta um atributo do formulrio, podemos acess-la a partir do mtodo button1_Click. Mas
ainda temos um erro de compilao porque o mtodo Deposita no existe na classe Conta. Ento vamos
cri-lo utilizando o Visual Studio. Dentro do mtodo button1_Click, coloque o cursor do teclado sobre o
mtodo Deposita e aperte Ctrl + ., e depois escolha a opo Generate Method stub for 'Deposita'in
'Banco.Conta'.
Com isso, o Visual Studio automaticamente colocar o mtodo dentro da classe Conta.
internal void Deposita(double p)
{
throw new NotImplementedException();
}
Apague a implementao padro desse mtodo, mude sua visibilidade para public e, por fm, faa a sua
implementao para a lgica de depsito. O cdigo deve fcar parecido com o que segue:
public void Deposita(double valorOperacao)
{
this.Saldo += valorOperacao;
}
Para terminar a lgica de depsito, precisamos apenas atualizar o valor do saldo na interface do usurio.
Abra novamente a ao do boto de depsito dentro do cdigo do formulrio principal da aplicao (m-
todo button1_Click da classe Form1). Dentro desse mtodo, vamos atualizar o texto mostrado no campo
textoSaldo com o valor do saldo da conta:
Captulo - Introduo ao Visual Studio com Windows Form - Operaes na conta: saque e depsito - Pgina
Material do Treinamento C e Orientao a Objetos
private void button1_Click(object sender, EventArgs e)
{
string valorDigitado = textoValor.Text;
double valorOperacao = Convert.ToString(valorDigitado);
this.c.Deposita(valorOperacao);
textoSaldo.Text = Convert.ToString(this.c.Saldo);
}
Para fnalizarmos essa ao, podemos avisar o usurio que a operao foi realizada com sucesso utilizando
ummessage box. Colocaremos a caixa de mensagemutilizando o atalho mbox + <tab> + <tab>, esse atalho
declara o cdigo do MessageBox.Show:
private void button1_Click(object sender, EventArgs e)
{
string valorDigitado = textoValor.Text;
double valorOperacao = Convert.ToString(valorDigitado);
this.c.Deposita(valorOperacao);
textoSaldo.Text = Convert.ToString(this.c.Saldo);
MessageBox.Show("Sucesso");
}
. CoN1notnNoo o Nomv on nXo ov cmno1Xo
Como vimos, a ao de umboto do formulrio ummtodo declarado na classe do formulrio que contm
o boto. Vimos tambm que o Visual Studio gera o nome dos mtodos na forma button<numero>_Click.
Esse um nome que pode facilmente causar confuso e gerar problemas de manuteno do cdigo.
Esse nome gerado pelo Visual Studio na verdade baseado na propriedade (Name) do componente Button.
Ento, para que o Visual Studio gere nomes mais amigveis para os botes, podemos simplesmente mudar
o (Name) do boto na janela Properties.
Vamos colocar umnovo boto no formulrio que implementar a operao de saque. Arraste umnovo boto
para o formulrio e como (Name) desse boto utilize botaoSaque. Agora d um duplo clique no novo boto
para gerar o cdigo de sua ao de clique. Isso criar um novo mtodo chamado botaoSaque_Click:
private void botaoSaque_Click(object sender, EventArgs e)
{
string valorDigitado = textoValor.Text;
double valorOperacao = Convert.ToString(valorDigitado);
this.c.Saca(valorOperacao);
textoSaldo.Text = Convert.ToString(this.c.Saldo);
MessageBox.Show("Sucesso");
}
Captulo - Introduo ao Visual Studio com Windows Form - Controlando o nome da ao de um boto - Pgina
Material do Treinamento C e Orientao a Objetos
Resta apenas implementarmos o mtodo Saca da Conta:
public void Saca(double valor)
{
this.Saldo -= valor;
}
Mude tambm o (Name) do boto de depsito para botaoDeposito. Na prxima seo aprenderemos como
renomear o nome da ao do boto sem causar problemas de compilao.
Tvx1o oo no1Xo
O texto de um boto do Windows Form tambm pode ser customizado atravs de sua proprie-
dade Text. Essa propriedade pode ser modifcada na janela properties do Visual Studio.
. RvNomvnNoo Vnn:Kvv:s, Mv1ooos v Ctnssvs com o V:scnt
S1co:o
Vamos olhar o cdigo do construtor do Cliente que implementamos anteriormente:
public class Cliente
{
public Cliente(string p)
{
this.Nome = p;
}
}
Veja que nesse cdigo estamos recebendo um parmetro chamado p, mas o que esse nome p signifca?
Quando criamos uma varivel, sempre importante utilizarmos nomes que descrevem sua funo dentro
do cdigo, se no podemos acabar difcultando a sua leitura e compreenso futuras.
Mas renomear uma varivel existente uma tarefa rdua, pois no adianta apenas renomearmos a declara-
o da varivel, precisamos tambm mudar todos os lugares que a utilizam. Quando queremos fazer uma
renomeao de variveis, podemos utilizar o prprio visual studio para fazer esse trabalho atravs do atalho
Ctrl + R, Ctrl + R (Ctrl + R duas vezes).
Vamos utilizar esse novo atalho para renomear o parmetro p recebido no construtor do Cliente. Para isso,
coloque o cursor do teclado sobre a declarao do parmetro p ou sobre umde seus usos e depois aperte Ctrl
+ R, Ctrl + R. Isso abrir uma nova janela onde podemos digitar qual o novo nome que queremos utilizar
para essa varivel. Digite nome na caixa de texto e depois confrme a mudana. Com isso o Visual Studio far
Captulo - Introduo ao Visual Studio com Windows Form - Renomeando Variveis, Mtodos e Classes com o Visual Studio -
Pgina
Material do Treinamento C e Orientao a Objetos
o rename automtico da varivel dentro do cdigo. O mesmo atalho pode ser usado para renomearmos
classes, mtodos, atributos e propriedades do cdigo.
Agora utilizaremos esse atalho de rename para modifcar o nome da ao do boto de depsito para
botaoDeposito_Click. Coloque o cursor do teclado sobre o nome do mtodo button1_Click da classe
Form1 E aperte Ctrl+R, Ctrl+R e renomeie o mtodo para botaoDeposito_Click.
Podemos tambm renomear argumento de mtodos utilizando esse atalho. Abra o mtodo Saca da classe
Conta e coloque o cursor do teclado sobre a varivel valorOperacao e depois aperte o Ctrl + R, Ctrl + R,
mude o nome da varivel para valor. Faa o mesmo com o mtodo Deposita.
No formulrio principal, a conta principal da aplicao est utilizando c como nome de varivel, porm c
no um bom nome, pois ele no um nome descritivo. Tente utilizar esse novo atalho que aprendemos
para mudar o nome desse atributo para conta, veja que o Visual Studio renomear tanto a declarao do
atributo quanto seus usos.
. Pnnn snnvn mn:s oncnN:znNoo o vonmctKn:o com Lnnvt
v GnocvBox
Neste captulo conseguimos mostrar as informaes da conta atravs da interface da aplicao, com isso o
usurio consegue saber o que est acontecendo com sua conta, porm uma caracterstica muito importante
de programas com interface grfca a organizao das informaes.
No formulrio que criamos, como o usurio sabe quais so os campos que representamo saldo, o nmero e o
titular da conta? Precisamos de alguma forma para indicar qual a informao que est armazenada dentro
de um TextBox, para isso utilizaremos um novo componente do Windows Form chamado Label. O label
funciona como uma etiqueta para nossos campos de texto. Atravs da propriedade Text da Label, que pode
ser modifcada pela janela properties, podemos defnir qual o texto que ser exibido. Veja como fca a
aplicao quando utilizamos o label:
Mas e quando temos uma interface grfca muito complexa? Nesses casos, podemos ter muitas funcionali-
dades ou informaes dentro de uma nica tela da aplicao. Para essa situao, uma prtica comum criar
Captulo - Introduo ao Visual Studio com Windows Form - Para saber mais organizando o formulrio com Label e
GroupBox - Pgina
Material do Treinamento C e Orientao a Objetos
grupos de elementos com funcionalidades semelhantes. Para organizar os grupos de componentes de um
formulrio, no Windows Form possumos mais um componente chamado GroupBox
Utilizando o GroupBox, podemos agrupar diversos componentes diferentes sob umnico ttulo. Oformulrio
do nosso projeto, por exemplo, fcaria da seguinte forma:
. Rvscmo oos n1ntnos oo V:scnt S1co:o
Para facilitar a consulta dos atalhos do Visual Studio, nessa seo vamos listar os atalhos vistos no captulo:
Ctrl + Shif + N: cria um novo projeto dentro do Visual Studio;
Ctrl + .: utilizado para fazer consertos rpidos no cdigo. Quando estamos utilizando uma classe
que no existe, ele declara a classe dentro do projeto. Ao utilizarmos uma propriedade ou mtodo
inexistente, o atalho cria automaticamente o cdigo para a propriedade ou mtodo;
Ctrl + R, Ctrl + R: renomeia classes, mtodos, propriedades, atributos ou variveis utilizadas no c-
digo;
Ctrl + <espao>: autocomplete;
Captulo - Introduo ao Visual Studio com Windows Form - Resumo dos atalhos do Visual Studio - Pgina
Material do Treinamento C e Orientao a Objetos
ctor + <tab> + <tab>: declara um construtor dentro da classe;
prop + <tab> + <tab>: declara uma propriedade dentro da classe;
mbox + <tab> + <tab>: declara o cdigo do MessageBox.Show().
. Exvncc:os
) Monte um formulrio que mostre os campos titular, saldo e numero de uma Conta. Faa com que a
varivel que guarda o campo titular seja chamada de textoTitular, a que guarda o saldo seja textoSaldo
e a que guarda o numero seja textoNumero.
No load do formulrio, escreva um cdigo que cria uma conta com titular Victor e numero . Mostre os
dados dessa conta nos campos textoTitular, textoSaldo e textoNumero do formulrio.
) Crie um novo campo de texto no formulrio chamado textoValor. Adicione tambm um novo boto
que quando clicado executar a lgica de depsito utilizando o valor digitado no campo criado. Depois
de executar a lgica, atualize o saldo atual que exibido pelo formulrio.
) Coloque um novo boto no formulrio. Faa com que a ao do clique desse boto execute um saque na
conta usando o valor do campo textoValor. Aps o saque, atualize as informaes que so exibidas para
o usurio.
. Pnnn snnvn mn:s 1:vos :mvtc:1os v n vntnvnn VAR
Umcliente precisa ser maior de idade ouemancipado para abrir uma conta no banco. Almdisso, ele tambm
precisa de um CPF. Para verifcar isso, o sistema possui um mtodo que verifca se um cliente pode ou no
abrir uma conta:
public bool PodeAbrirContaSozinho
{
get
{
return (this.idade >= 18 ||
this.documentos.contains("emancipacao")) &&
!string.IsNullOrEmpty(this.cpf);
}
}
Perceba que podemos criar trs variveis para que nosso if no fque muito complexo:
public bool PodeAbrirContaSozinho
{
Captulo - Introduo ao Visual Studio com Windows Form - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
get
{
bool maiorDeIdade = this.idade >= 18;
bool emancipado = this.documentos.contains("emancipacao");
bool possuiCPF = !string.IsNullOrEmpty(this.cpf);
return (maiorDeIdade || emancipado) && possuiCPF;
}
}
Desse jeito, o cdigo fca mais limpo e fcil de entender. Porm, tivemos que fcar declarando os tipos das
variveis como bool. No seria bvio para o C que essas variveis so do tipo bool. Sim! E ele esperto o
sufciente para inferir isso:
public bool PodeAbrirContaSozinho
{
get
{
var maiorDeIdade = this.idade >= 18;
var emancipado = this.documentos.contains("emancipacao");
var possuiCPF = !string.IsNullOrEmpty(this.cpf);
return (maiorDeIdade || emancipado) && possuiCPF;
}
}
Variveis dentro de mtodos podem ser declaradas como var em C que o seu tipo inferido automatica-
mente. Para o compilador acertar qual o tipo da varivel ela deve ser inicializada no mesmo instante que
declarada e no pode ser atribudo o valor null.
public bool PodeAbrirContaSozinho
{
get
{
var maiorDeIdade; // esta linha no compila
maiorDeIdade = this.idade >= 18;
// ...
}
}
Por fm, uma varivel declarada como var possui um tipo bem defnido e no pode ser alterado. A tipagem
inferida, mas o tipo da varivel no pode ser alterada medida que o cdigo executado, o que faz com
que o cdigo seguinte no faa sentido e no compile:
var guilherme = new Cliente();
guilherme = new Conta();
Captulo - Introduo ao Visual Studio com Windows Form - Para saber mais tipos implcitos e a palavra VAR - Pgina
Material do Treinamento C e Orientao a Objetos
. Exvncc:os Ovc:oNn:s
) Observe o cdigo a seguir e assinale a alternativa correta.
var conta = new Conta();
conta.Titular = new Cliente();
No compila pois a varivel de um tipo dinmico.
Compila e faz com que a varivel conta possa referenciar qualquer tipo de objeto.
No compila pois ele no tem como adivinhar se var uma conta nova ou j existente.
Compila e faz com que a varivel conta seja do tipo Conta.
) O que acontece ao tentar compilar e rodar o cdigo a seguir?
var simples = new Conta(); // linha 1
simples = new Conta(); // linha 2
simples = new Cliente(); // linha 3
A linha no compila pois no podemos reatribuir uma varivel.
A linha no compila pois o tipo de uma varivel no pode ser trocado e ele inferido ao declarar
a varivel.
Compila e no fm das linhas de cdigo a varivel simples apontar para um Cliente.
A linha no compila devido ao cdigo da linha e .
) O que acontece ao compilar e rodar o cdigo a seguir?
var conta;
conta = new Conta();
conta.Deposita(300);
No compila pois conta no teve um valor atribudo j na primeira linha.
Compila mas no roda, dando erro de execuo na linha pois tentamos acessar uma varivel sem
valor.
Compila e roda.
) O que acontece ao compilar e executar o cdigo adiante?
var tamanho = 5;
tamanho = tamanho / 2.0;
MessageBox.Show(tamanho);
O cdigo no compila na linha .
O cdigo compila e roda imprimindo .
Captulo - Introduo ao Visual Studio com Windows Form - Exerccios Opcionais - Pgina
Material do Treinamento C e Orientao a Objetos
O cdigo compila mas no roda pois no divisvel por ..
O cdigo compila e roda, imprimindo tamanho = .
Captulo - Introduo ao Visual Studio com Windows Form - Exerccios Opcionais - Pgina
C
Herana
Imagine agora que nosso banco realize depsitos e saques de acordo com o tipo da conta. Se a conta for
poupana, o cliente deve pagar . por saque. Se a conta for corrente, no h taxa.
Para implementar essa regra de negcio, vamos colocar um if no mtodo Saca:
public void Saca(double valor)
{
if(this.Tipo == ???????????)
{
this.Saldo -= valor + 0.10;
}
else
{
this.Saldo -= valor;
}
}
Podemos criar um atributo na Conta, que especifca o tipo da conta como, por exemplo, um inteiro qualquer
onde o nmero representaria conta poupana e conta corrente.
A implementao seria algo como:
public class Conta
{
public int Numero { get; set;}
public double Saldo { get; private set; }
public Cliente Titular { get; set; }
Material do Treinamento C e Orientao a Objetos
public int Tipo { get; set; }
public void Saca(double valor)
{
if(this.Tipo == 1)
{
this.Saldo -= valor + 0.10;
}
else
{
this.Saldo -= valor;
}
}
public void Deposita(double valor)
{
this.Saldo += valor;
}
}
Veja que uma simples regra de negcio como essa fez nosso cdigo crescer muito. Epoderia ser pior: imagine
se nosso banco tivesse tipos de contas diferentes. Esse if seria maior ainda.
Precisamos encontrar uma maneira de fazer com que a criao de novos tipos de conta no implique em um
aumento de complexidade.
. Rvnvnovv:1nNoo coo:co comn HvnnNn
Uma soluo seria ter classes separadas para Conta (que a corrente) e ContaPoupanca:
public class Conta
{
public int Numero { get; set;}
public double Saldo { get; private set; }
public Cliente Titular { get; set; }
public void Saca(double valor)
{
this.Saldo -= valor;
}
public void Deposita(double valor)
Captulo - Herana - Reaproveitando cdigo com a Herana - Pgina
Material do Treinamento C e Orientao a Objetos
{
this.Saldo += valor;
}
}
public class ContaPoupanca
{
public int Numero { get; set;}
public double Saldo { get; private set; }
public Cliente Titular { get; set; }
public void Saca(double valor)
{
this.Saldo -= (valor + 0.10);
}
public void Deposita(double valor)
{
this.Saldo += valor;
}
}
Ambas as classes possuem cdigo bem simples, mas agora o problema outro: a repetio de cdigo entre
ambas as classes. Se amanh precisarmos guardar CPF, por exemplo, precisaremos mexer em todas as
classes que representam uma conta no sistema. Isso pode ser trabalhoso.
Aideia , portanto, reaproveitar cdigo. Veja que, no fm, uma ContaPoupanca uma Conta, pois ambos tem
Numero, Saldo e Titular. A nica diferena o comportamento no momento do saque. Podemos falar que
uma ContaPoupanca uma Conta:
public class ContaPoupanca : Conta
{
}
Quando uma classe defnida com o :, dizemos que ela herda da outra (Conta) e por isso ela ganha todos
os atributos e mtodos da outra classe. Por exemplo, se ContaPoupanca herdar de Conta, isso quer dizer que
ela ter Numero, Saldo, Titular, Saca() e Deposita() automaticamente, sem precisar fazer nada. Dizemos
que a classe ContaPoupanca uma subclasse ou classe flha da classe Conta e que Conta uma classe base
ou classe pai da ContaPoupanca. Veja o cdigo a seguir:
// Arquivo ContaPoupanca.cs
public class ContaPoupanca : Conta
Captulo - Herana - Reaproveitando cdigo com a Herana - Pgina
Material do Treinamento C e Orientao a Objetos
{
}
// Cdigo no formulrio que utiliza a ContaPoupanca
ContaPoupanca c = new ContaPoupanca();
c.Deposita(100.0);
Basta usar a notao : e o C automaticamente herda os mtodos e atributos da classe pai. Mas a
ContaPoupanca tem o comportamento de Saca() diferente. Para isso, basta reescrever o comportamento
na classe flha, usando a palavra override e mudando a classe pai para indicar que o mtodo pode ser so-
brescrito (virtual):
// Arquivo Conta.cs
public class Conta
{
public virtual void Saca(double valor)
{
this.Saldo -= valor;
}
// Resto do cdigo da classe
}
// Arquivo ContaPoupanca.cs
public class ContaPoupanca : Conta
{
public override void Saca(double valor)
{
this.Saldo -= (valor + 0.10);
}
}
// Cdigo do formulrio da aplicao
ContaPoupanca c = new ContaPoupanca();
// chama o comportamento escrito no pai
// O Saldo termina em 100.0 depois dessa linha
c.Deposita(100.0);
// chama o comportamento escrito na ContaPoupanca
// O Saldo termina com o valor 49.90
c.Saca(50);
Captulo - Herana - Reaproveitando cdigo com a Herana - Pgina
Material do Treinamento C e Orientao a Objetos
Veja nesse cdigo que invocamos tanto Deposita() quanto Saca(). No depsito, como a classe flha no
redefniu o comportamento, o mtodo escrito na classe pai ser utilizado.
J no saque, o comportamento usado o que foi sobrescrito na classe flha.
Mas o cdigo anterior ainda no compila. Repare que o mtodo Saca() da ContaPoupanca manipula o Saldo.
Mas Saldo privado! Atributos privados s so visveis para a classe que os declarou. Os flhos no enxergam.
Queremos proteger nosso atributo mas no deix-lo privado nem pblico. Queremos proteger o sufciente
para ningum de fora acessar, mas apenas quem herda ter acesso. Para resolver, alteraremos o modifcador
de acesso para protected. Atributos/mtodos marcados como protected so visveis apenas para a prpria
classe e para as classes flhas:
public class Conta
{
public int Numero { get; set;}
public double Saldo { get; protected set; }
// ...
}
A classe Conta ainda pode ser instanciada sem problemas:
Conta c = new Conta();
c.Deposita(100.0);
Veja que com herana conseguimos simplifcar e reutilizar cdigo ao mesmo tempo. A herana um meca-
nismo poderoso mas deve ser utilizado com cuidado.
. Rvnvnovv:1nNoo n :mvtvmvN1nXo on ctnssv nnsv
Observe as implementaes dos mtodos Saca das classes Conta e ContaPoupanca:
public class Conta
{
// outros atributos e mtodos
public double Saldo { get; protected set; }
public virtual void Saca(double valor)
{
this.Saldo -= valor;
}
}
Captulo - Herana - Reaproveitando a implementao da classe base - Pgina
Material do Treinamento C e Orientao a Objetos
public class ContaPoupanca : Conta
{
public override void Saca(double valor)
{
this.Saldo -= (valor + 0.10);
}
}
As implementaes dos dois mtodos so praticamente iguais, a nica diferena que no Saca da
ContaPoupanca colocamos this.Saldo -= (valor + 0.10); ao invs de this.Saldo -= valor;.
Quando fazemos a sobrescrita de mtodos em uma classe flha, muitas vezes, queremos apenas mudar le-
vemente o comportamento da classe base. Nessas situaes, no cdigo da classe flha, podemos reutilizar o
cdigo da classe pai com a palavra base chamando o comportamento que queremos reaproveitar. Ento o
cdigo do Saca da ContaPoupanca poderia ser reescrito da seguinte forma:
public class ContaPoupanca : Conta
{
public override void Saca(double valor)
{
base.Saca(valor + 0.10);
}
}
Com essa implementao, o Saca da ContaPoupanca chama o mtodo da classe base passando como argu-
mento valor + 0.10. Repare tambm que, como a classe flha no est utilizando a propriedade Saldo da
Conta, ela poderia voltar a ser private:
public class Conta
{
public double Saldo { get; private set; }
// outras propriedades e mtodos
}
. Pot:monv:smo
Nosso banco temrelatrios internos para saber como est a sade fnanceira da instituio, almde relatrios
sobre os clientes e contas. Em um deles, necessrio calcular a soma do saldo de todas as contas (correntes,
poupanas, entre outras) que existem no banco. Comeando com zero reais":
public class TotalizadorDeContas
{
Captulo - Herana - Polimorfsmo - Pgina
Material do Treinamento C e Orientao a Objetos
public double ValorTotal { get; private set; }
}
Permitimos adicionar Conta ao nosso relatrio e acumular seu saldo:
public class TotalizadorDeContas
{
public double ValorTotal { get; private set; }
public void Soma(Conta conta)
{
ValorTotal += conta.Saldo;
}
}
Conta c1 = new Conta();
Conta c2 = new Conta();
TotalizadorDeContas t = new TotalizadorDeContas();
t.Soma(c1);
t.Soma(c2);
timo. Mas o problema que temos classes que representamdiferentes tipos de contas, e queremos acumular
o saldo delas tambm. Uma primeira soluo seria ter um mtodo Soma() para cada classe especfca:
public class TotalizadorDeContas
{
public double ValorTotal { get; private set; }
public void Soma(Conta conta) { /* ... */ }
public void Soma(ContaPoupanca conta) { /* ... */ }
public void Soma(ContaEstudante conta) { /* ... */ }
// mais um monte de mtodos aqui!
}
Novamente camos no problema da repetio de cdigo.
Veja que ContaPoupanca uma Conta. Isso inclusive expresso atravs da relao de herana entre as classes.
E, j que ContaPoupanca uma Conta, o C permite que voc passe ContaPoupanca em lugares que aceitam
referncias do tipo Conta! Linguagens orientadas a objetos, como C, possuem essa soluo elegante pra
isso.
Veja o cdigo a seguir:
Captulo - Herana - Polimorfsmo - Pgina
Material do Treinamento C e Orientao a Objetos
public class TotalizadorDeContas
{
public double ValorTotal { get; private set; }
public void Soma(Conta conta)
{
ValorTotal += conta.Saldo;
}
}
Conta c1 = new Conta();
ContaPoupanca c2 = new ContaPoupanca();
TotalizadorDeContas t = new TotalizadorDeContas();
t.Soma(c1);
t.Soma(c2); // funciona!
O cdigo funciona! Podemos passar c2 ali para o mtodo Soma().
Mas como isso funciona? O C sabe que ContaPoupanca herda todos os atributos e mtodos de Conta, e
portanto, tem a certeza de que existe o atributo Saldo, e que ele poder invoc-lo sem maiores problemas!
Agora, uma ContaPoupanca temumnovo comportamento, que permite calcular seus rendimentos. Para isso
o desenvolvedor criou um comportamento chamado CalculaRendimento():
class ContaPoupanca : Conta
{
public void CalculaRendimento()
{
// ...
}
}
Veja o mtodo Soma(). Ele invoca tambm o CalculaRendimento():
public class TotalizadorDeContas
{
public double ValorTotal { get; private set; }
public void Soma(Conta conta)
{
ValorTotal += conta.Saldo;
conta.CalculaRendimento(); // no compila!
}
}
Captulo - Herana - Polimorfsmo - Pgina
Material do Treinamento C e Orientao a Objetos
O cdigo anterior no compila. Por qu? Porque o C no consegue garantir que o que vir na varivel
conta ser uma ContaPoupanca. Naquela porta entra Conta ou qualquer flho de Conta. Portanto, tudo o
que o C consegue garantir que o objeto que entrar ali tem tudo que Conta tem. Por isso, s podemos usar
mtodos e atributos defnidos pelo tipo da varivel (no caso, Conta.)
Essa ideia de uma variavel conseguir referenciar seu prprio tipo ou flhos desse tipo conhecido por poli-
morfsmo. Veja que, com o uso de polimorfsmo, garantimos que a classe TotalizadorDeContas funcionar
para todo novo tipo de Conta que aparecer.
Se no futuro um novo tipo de conta, como conta investimento, for criada, basta que ela herde de Conta e no
precisaremos nunca modifcar essa classe! Ela funcionar naturalmente!
Um programador que conhece bem orientao a objetos faz uso constante de polimorfsmo. Veremos mais
pra frente como continuar usando polimorfsmo para escrever cdigo de qualidade, tomando cuidado para
no abusar dessa ideia.
. Exvncc:os
) Qual a diferena entre private e protected?
Nenhuma. Em ambos, o atributo/mtodo visvel para todos.
S a prpria classe enxerga atributos/mtodos private enquanto protected visto pela prpria
classe mais as classes flhas.
S a prpria classe enxerga atributos/mtodos protected enquanto private visto pela prpria
classe mais as classes flhas.
) Para que serve a palavra override?
Para indicar que o mtodo est sobrescrevendo um mtodo da classe pai.
Para no permitir acesso ao atributo por outras classes.
Para indicar que esse mtodo no deve ser utilizado.
) Pra que serve a palavra virtual?
Para permitir que o mtodo seja sobrescrito.
Para indicar que esse mtodo no deve ser sobrescrito.
Para sobrescrever um mtodo da classe pai.
Para no permitir acesso ao atributo por outras classes.
) Adicione a classe ContaPoupanca na aplicao. Essa classe deve herdar da Conta e sobrescrever o com-
portamento do mtodo Saca para que todos os saques realizados na conta poupana paguem uma taxa
de R ..
Captulo - Herana - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
No se esquea de utilizar as palavras virtual e override para sobrescrever os mtodos.
) O que acontece ao executarmos o cdigo a seguir:
Conta c1 = new ContaPoupanca();
c1.Deposita(100.0);
c1.Saca(50.0);
MessageBox.Show("conta poupana = " + c1.Saldo);
Conta c2 = new Conta();
c2.Deposita(100.0);
c2.Saca(50.0);
MessageBox.Show("conta = " + c2.Saldo);
conta poupanca = . e conta = .
conta poupana = . e conta = .
conta poupana = . e conta = .
conta poupana = . e conta = .
) Faa com que o mtodo Form1_Load, instancie uma ContaPoupanca ao invs da Conta:
public partial class Form1 : Form
{
// Essa a mesma declarao que colocamos no captulo anterior
private Conta conta;
private void Form1_Load(object sender, EventArgs e)
{
this.conta = new ContaPoupanca();
// resto do cdigo continua igual
}
// cdigo do resto do formulrio tambm continua igual
}
Repare que no precisamos modifcar o tipo da varivel conta, pois como a ContaPoupanca herda de
Conta, podemos utilizar o polimorfsmo para atribuir uma referncia do tipo ContaPoupanca em uma
varivel do tipo Conta.
Depois de modifcar o programa, execute-o e teste a operao de depsito. Repare que na classe
ContaPoupanca no declaramos o mtodo Deposita, mas mesmo assim conseguimos invoc-lo dentro
do cdigo, isso possvel pois quando utilizamos herana, todo o comportamento da classe pai herdado
pela classe flha.
Teste tambm o boto de saque. Como a ContaPoupanca sobrescreve o mtodo Saca da Conta, ao aper-
tarmos o boto de saque, estamos invocando o comportamento especializado que foi implementado na
ContaPoupanca ao invs de usar o que foi herdado da Conta.
Captulo - Herana - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) Crie a classe ContaCorrente dentro do projeto e faa com que ela herde da classe Conta.
Todas as operaes na ContaCorrente sero tarifadas, em todo Saque, precisamos pagar uma taxa de R
. e para os depsitos, R ., ou seja, na ContaCorrente, precisaremos sobrescrever tanto o mtodo
Saca quanto o Deposita. No se esquea de usar o virtual e override para fazer a sobrescrita no cdigo.
Depois de criar a ContaCorrente, modifque novamente o formulrio para que ele mostre as informaes
de uma ContaCorrente ao invs de uma ContaPoupanca.
) (Opcional) Implemente a classe TotalizadorDeContas comuma propriedade chamada SaldoTotal e um
mtodo chamado Adiciona que deve receber uma conta e somar seu saldo ao saldo total do totalizador.
Escreva um cdigo que testa o totalizador.
Podemos passar uma instncia de ContaCorrente para o Adiciona do totalizador? Por qu?
. Pnnn snnvn mn:s o qcv v nvnonoo:
Neste captulo, vimos que quando fazemos a classe ContaPoupanca herdar da classe Conta, ela recebe automa-
ticamente todos os atributos, propriedades e mtodos da classe pai, porm os construtores da classe pai no
so herdados. Ento se a classe flha precisa de um construtor que est na classe pai, ela deve explicitamente
declarar esse construtor em seu cdigo.
Imagine por exemplo, que para construirmos a conta precisamos passar opcionalmente seu nmero:
public class Conta
{
public int Numero { get; set; }
// Construtor sem argumentos
public Conta() {}
public Conta(int numero)
{
this.Numero = numero;
}
}
Agora na classe ContaPoupanca queremos passar o nmero na construo do objeto, como o construtor no
herdado, precisamos colocar a declarao explicitamente:
public class ContaPoupanca : Conta
{
public ContaPoupanca(int numero)
{
// A propriedade Numero veio herdada da classe Conta
Captulo - Herana - Para saber mais o que herdado? - Pgina
Material do Treinamento C e Orientao a Objetos
this.Numero = numero;
}
}
Nesse construtor que acabamos de declarar na classe ContaPoupanca, fzemos apenas a inicializao da pro-
priedade nmero, exatamente o mesmo cdigo que temos no construtor da classe pai, ento ao invs de
repetirmos o cdigo, podemos simplesmente chamar o construtor que foi declarado na classe Conta a partir
do construtor da classe ContaPoupanca utilizando a palavra base:
public class ContaPoupanca : Conta
{
// Estamos chamando o construtor da classe pai que j faz a inicializao
// do nmero e por isso o corpo do construtor pode ficar vazio.
public ContaPoupanca(int numero) : base (numero) { }
}
Na verdade, dentro do C, sempre que construmos uma instncia de ContaPoupanca, o C sempre precisa
chamar um construtor da classe Conta para fazer a inicializao da classe base. Quando no invocamos
explicitamente o construtor da classe pai, o C coloca implicitamente uma chamada para o construtor sem
argumentos da classe pai:
public class ContaPoupanca : Conta
{
// nesse cdigo o c# chamar o construtor sem argumentos da classe Conta.
public ContaPoupanca(int numero)
{
this.Numero = numero;
}
}
Se a classe Conta no defnir o construtor semargumentos, temos umerro de compilao se no invocarmos
explicitamente um construtor da classe pai.
Captulo - Herana - Para saber mais o que herdado? - Pgina
C
Trabalhando com arrays
Queremos guardar uma lista de contas de nosso banco para poder trabalhar com elas. Uma primeira alter-
nativa seria criar um conjunto de variveis, no qual cada varivel aponta para uma Conta diferente:
Conta c1 = new Conta();
Conta c2 = new ContaPoupanca();
Conta c3 = new Conta();
// ...
Mas, e se quisermos imprimir o saldo de todas elas? Precisaremos escrever N linhas, uma para cada Conta:
MessageBox.Show(c1.Titular.Nome);
MessageBox.Show(c2.Titular.Nome);
MessageBox.Show(c3.Titular.Nome);
Muito trabalho! Criar uma nova Conta seria um caos!
Quando queremos guardar diversos objetos, podemos fazer uso de Arrays. Um array uma estrutura de
dados que consegue guardar vrios elementos e ainda nos possibilita pegar esses elementos de maneira fcil!
Criar um array muito parecido com instanciar uma classe. Para criarmos posies de nmeros inteiros:
int[] numeros = new int[5];
Acabamos de declarar um array de inteiros, com posies. Repare a notao [5]. Para guardar elementos
nessas posies, fazemos:
numeros[0] = 1;
numeros[1] = 600;
Material do Treinamento C e Orientao a Objetos
numeros[2] = 257;
numeros[3] = 12;
numeros[4] = 42;
MessageBox.Show("nmero = " + numeros[1]);
Veja que a primeira posio de um array 0 (zero). Logo, as posies de um array vo de 0 (zero) at
(tamanho-1).
Vamos agora criar um array de Contas:
Conta[] contas = new Conta[5];
contas[0] = new Conta();
A sintaxe a mesma. Os elementos guardados pelo array so iguais aos de uma varivel convencional, que
voc j est acostumado. Isso quer dizer que temos polimorfsmo tambm! Ou seja, podemos guardar, em
um array de Conta, qualquer flho dela:
contas[1] = new ContaPoupanca();
Se quisermos imprimir todas as Contas armazenadas, podemos fazer um loop nesse array. O loop comear
em 0 e ir at o tamanho do array (contas.Length):
for(int i = 0; i < contas.Length; i++)
{
MessageBox.Show("saldo = " + contas[i].Saldo);
}
Podemos ainda usar uma outra sintaxe do C, afnal queremos ir para cada Conta c em contas:
foreach(Conta c in contas)
{
MessageBox.Show("saldo = " + c.Saldo);
}
O C pega cada elemento do array e coloca automaticamente na varivel c, imprimindo o resultado que
queremos.
. Pnnn snnvn mn:s :N:c:nt:znXo ov Annnvs
Em muitas situaes, estamos interessados em criar e logo em seguida inicializar o contedo de um array,
para isso, como vimos nesse captulo, precisaramos de um cdigo parecido com o que segue:
Captulo - Trabalhando com arrays - Para saber mais inicializao de Arrays - Pgina
Material do Treinamento C e Orientao a Objetos
int[] inteiros = new int[5];
inteiros[0] = 1;
inteiros[1] = 2;
inteiros[2] = 3;
inteiros[3] = 4;
inteiros[4] = 5;
Veja que esse cdigo repetitivo e fcil de ser escrito de forma incorreta. Para facilitar nosso trabalho, o
C nos oferece um atalho para criar e inicializar o contedo do array. Se quisssemos um array de inteiros
preenchido com os nmeros de a , poderamos utilizar o seguinte cdigo:
int[] umAoCinco = new int[] { 1, 2, 3, 4, 5 };
Essa sintaxe pode ser utilizada em arrays de qualquer tipo.
. Exvncc:os
) Qual das linhas a seguir instancia um array de elementos?
int[] numeros = new int[];
int[] numeros = new int[];
int[] numeros = new int["dez"];
int[] numeros = new int[];
) Imagine o array abaixo:
int[] numeros = new int[15];
Como acessar o quinto elemento nessa lista?
numeros[]
numeros[]
numeros["quinto"]
numeros[]
) Dado um array numero, como descobrir seu tamanho?
numero.Length
numero.Size
numero.Size()
Captulo - Trabalhando com arrays - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
numero.Length()
numero.Capacity()
) Agora vamos utilizar arrays no projeto do banco para trabalharmos comdiversas contas ao mesmo tempo.
Dentro da classe do formulrio da aplicao, a classe Form1 criada pelo Visual Studio, vamos guardar um
array de contas ao invs de uma nica conta.
public partial class Form1 : Form
{
// vamos substituir conta por um array de contas.
// Apague a linha:
// private Conta conta;
// E coloque a declarao do array em seu lugar:
private Conta[] contas;
// resto da classe
}
No mtodo Form1_Load, vamos inicializar o array de contas do formulrio e, ao invs de criarmos uma
nica conta, vamos criar diversas contas e guard-las dentro do array.
private void Form1_Load(object sender, EventArgs e)
{
// criando o array para guardar as contas
contas = new Conta[3];
// vamos inicializar algumas instncias de Conta.
this.contas[0] = new Conta();
this.contas[0].Titular = new Cliente("victor");
this.contas[0].Numero = 1;
this.contas[1] = new ContaPoupanca();
this.contas[1].Titular = new Cliente("mauricio");
this.contas[1].Numero = 2;
this.contas[2] = new ContaCorrente();
this.contas[2].Titular = new Cliente("osni");
this.contas[2].Numero = 3;
}
No formulrio, para sabermos qual a conta que deve ser exibida, colocaremos um novo campo de texto
onde o usurio escolher qual o ndice da Conta que ser utilizada. Chame esse campo de texto de
textoIndice. Alm do campo de texto, adicione tambm um novo boto que quando clicado mostrar a
conta do ndice que o usurio selecionou.
O seu formulrio deve fcar parecido com o da imagem:
Captulo - Trabalhando com arrays - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Utilize botaoBusca como (Name) desse novo boto.
Quando o usurio clicar no botaoBusca, precisamos mostrar a conta que foi selecionada:
private void botaoBusca_Click(object sender, EventArgs e)
{
int indice = Convert.ToInt32(textoIndice.Text);
Conta selecionada = this.contas[indice];
textoNumero.Text = Convert.ToString(selecionada.Numero);
textoTitular.Text = selecionada.Titular.Nome;
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
}
No boto de depsito, precisamos depositar o valor na conta que foi escolhida pelo usurio no
textoIndice. Em nosso exemplo, se o usurio digitar 1 no textoIndice, precisamos fazer o depsito
na conta do titular mauricio (que est na posio 1 do array).
private void botaoDeposito_Click(object sender, EventArgs e)
{
// primeiro precisamos recuperar o ndice da conta selecionada
int indice = Convert.ToInt32(textoIndice.Text);
// e depois precisamos ler a posio correta do array.
Conta selecionada = this.contas[indice];
double valor = Convert.ToDouble(textoValor.Text);
selecionada.Deposita(valor);
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
}
Faa o mesmo para a ao do boto de Saque. Depois de fazer todas as modifcaes, teste a aplicao
fazendo, por exemplo, um depsito na conta que est no ndice 0.
Captulo - Trabalhando com arrays - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Tente fazer operaes em diferentes tipos de conta. Veja que dependendo do tipo de conta que foi cadas-
trada no array, teremos um resultado diferente para as operaes de saque e depsito. Note que o cdigo
do formulrio no precisa conhecer as contas que esto gravadas no array, ele precisa apenas utilizar os
mtodos que esto na interface de uso da conta.
. OncnN:znNoo ns coN1ns como ComnoBox
Na aplicao, estamos gerenciando as contas cadastradas atravs de um campo de texto. Essa uma aborda-
gem bem simples, mas que possui diversos problemas:
O cdigo espera que o usurio digite um nmero no campo de texto. Se ele digitar uma letra ou
qualquer outro caractere no numrico, teremos um erro;
O nmero digitado deve ser um ndice vlido do array ou novamente teremos um erro no cdigo.
Seria muito melhor se o usurio pudesse escolher uma conta cadastrada a partir de uma lista gerenciada
pela aplicao. Para implementarmos essa ideia, vamos utilizar um novo componente do Windows Form
chamado ComboBox.
Para adicionar um combo box no formulrio, precisamos apenas abrir a janela Toolbox (Ctrl+W, X) e arras-
tar o combo box para dentro do formulrio.
Para inserir os elementos que sero exibidos no combo box, precisaremos de uma varivel que guarda a
referncia para o componente. Assim como no campo de texto, podemos defnir o nome dessa varivel
atravs da janela properties.
Para acessar a janela properties do combo box, clique com o boto direito do mouse no combo box e
selecione a opo Properties.
Dentro da janela properties, utilizaremos novamente o campo (Name) para defnir o nome da varivel que
guardar a referncia para o combo box. Vamos utilizar comboContas.
Agora precisamos mostrar os titulares das contas como itens do combo box. Para adicionar um novo item
no combo box, utilizamos o seguinte cdigo:
comboContas.Items.Add("Texto que aparecer no combo box");
Captulo - Trabalhando com arrays - Organizando as contas com o ComboBox - Pgina
Material do Treinamento C e Orientao a Objetos
Logo, para mostrar os titulares como itens do combo box, utilizamos o seguinte cdigo;
comboContas.Items.Add(contas[0].Titular.Nome);
comboContas.Items.Add(contas[1].Titular.Nome);
Ou podemos utilizar um foreach:
foreach(Conta conta in contas)
{
comboContas.Items.Add(conta.Titular.Nome);
}
Agora que j conseguimos mostrar o combo box, queremos que a escolha de uma opo no combo, faa com
que o formulrio mostre a conta do titular selecionado.
Para associar uma ao ao evento de mudana de seleo do combo, precisamos apenas dar um duplo clique
no combo box. Isso criar um novo mtodo na classe Form1:
private void comboContas_SelectedIndexChanged(object sender, EventArgs e)
{
}
Podemos recuperar qual o ndice (comeando de zero) do item que foi selecionado pelo usurio lendo a
propriedade SelectedIndex do comboContas:
int indice = comboContas.SelectedIndex;
Esse ndice representa qual o elemento do array de contas que foi selecionado, logo, podemos us-lo para
recuperar a conta que foi escolhida:
Conta selecionada = contas[indice];
Depois de descobrir qual a conta escolhida, vamos mostr-la no formulrio:
Captulo - Trabalhando com arrays - Organizando as contas com o ComboBox - Pgina
Material do Treinamento C e Orientao a Objetos
textoTitular.Text = selecionada.Titular.Nome;
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
textoNumero.Text = Convert.ToString(selecionada.Numero);
O cdigo completo do comboContas_SelectedIndexChanged fca da seguinte forma:
private void comboContas_SelectedIndexChanged(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
Conta selecionada = contas[indice];
textoTitular.Text = selecionada.Titular.Nome;
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
textoNumero.Text = Convert.ToString(selecionada.Numero);
}
. Exvncc:os
) Vamos substituir o campo de texto que seleciona a conta para as operaes por um combo box. No
formulrio da aplicao apague o campo textoIndice, o botaoBusca e o mtodo botaoBusca_Click.
Esses dois componentes sero substitudos pelo combo box.
Agora abra a janela Toolbox do Visual Studio e arraste umComboBox para a aplicao. Chame componente
de comboContas. Seu formulrio deve fcar como o a seguir:
Na ao de carregamento do formulrio, vamos cadastrar as contas do array dentro do combo box. Para
isso, precisamos chamar o mtodo Add da propriedade Items do comboContas passando qual o texto
que queremos mostrar como opo do combo box.
private void Form1_Load(object sender, EventArgs e)
{
Captulo - Trabalhando com arrays - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
// cdigo de inicializao do array de contas
foreach(Conta conta in contas)
{
comboContas.Items.Add("titular: " + conta.Titular.Nome);
}
}
Quando o usurio modifcar o valor do combo box, queremos mudar a conta que exibida no formulrio.
Para criarmos o mtodo que cuidar do evento de mudana de itemselecionado do combo box, d umdu-
plo clique no componente. Isso criar dentro do Form1 o mtodo comboContas_SelectedIndexChanged:
private void comboContas_SelectedIndexChanged(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
Conta selecionada = this.contas[indice];
textoNumero.Text = Convert.ToString(selecionada.Numero);
textoTitular.Text = selecionada.Titular.Nome;
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
}
Agora faa com que os botes Depositar e Sacar (mtodos botaoDeposito_Click e botaoSaque_Click,
respectivamente) operem na conta selecionada pelo combo box.
) (Opcional) Vamos agora adicionar a lgica de transferncia no formulrio. Adicione umnovo combo box
no formulrio chamado comboDestinoTransferencia e um novo boto que, quando clicado, transfere
dinheiro da conta selecionada no comboContas para a conta selecionada no comboDestinoTransferencia.
Captulo - Trabalhando com arrays - Exerccios - Pgina
C
Cadastro de novas contas
At agora, temos em nossa aplicao um caixa eletrnico com um nmero fxo de contas, nesse captulo,
vamos fazer um novo formulrio para cadastrar as contas no caixa eletrnico.
Para no colocarmos ainda mais campos no formulrio principal, vamos criar um novo formulrio no pro-
jeto. Abra o Solution Explorer, clique com o boto direito no projeto Banco e selecione Add > New Item.
Na nova janela, selecione a opo Windows Form e coloque FormCadastroConta.cs no campo Name. Em
seguida, clique no boto Add.
Material do Treinamento C e Orientao a Objetos
Agora que terminamos de criar o novo formulrio, vamos adicionar um campo de texto para o titular da
conta (chamado textoTitular) e umpara o nmero da conta (chamado textoNumero). Almdesses campos,
precisaremos tambmde umboto que, quando clicado, realizar o cadastro da nova conta. Adicione o boto
e chame-o de botaoCadastro
Vamos defnir a ao do boto de cadastro desse novo formulrio. D um duplo clique no boto que acaba-
mos de criar. Isso abrir novamente o editor do Visual Studio:
public partial class FormCadastroConta : Form
{
public FormCadastroConta()
{
InitializeComponent();
}
private void botaoCadastro_Click(object sender, EventArgs e)
{
Captulo - Cadastro de novas contas - - Pgina
Material do Treinamento C e Orientao a Objetos
}
}
Na ao do boto, queremos criar uma nova instncia de conta, ContaCorrente por exemplo, e depois pre-
encher os seus dados:
private void botaoCadastro_Click(object sender, EventArgs e)
{
Conta novaConta = new ContaCorrente();
novaConta.Titular = new Cliente(textoTitular.Text);
novaConta.Numero = Convert.ToInt32(textoNumero.Text);
}
Agora que inicializamos a conta, precisamos cadastr-la no array que est na classe Form1. Precisamos, por-
tanto, acessar a instncia de Form1 a partir de FormCadastroConta. Queremos garantir que, na construo
do FormCadastroConta, teremos a instncia de Form1, portanto vamos modifcar o construtor da classe para
receber o formulrio principal:
public partial class FormCadastroConta : Form
{
private Form1 formPrincipal;
public FormCadastroConta(Form1 formPrincipal) {
this.formPrincipal = formPrincipal;
InitializeComponent();
}
// Ao de cadastro de conta
}
Precisamos colocar a conta criada no array que contm todas as contas cadastradas que est no formulrio
principal da aplicao.
Para fazer isso, podemos mudar a visibilidade do atributo (deixar o contas pblico), mas isso uma violao
de encapsulamento, estamos claramente vendo os detalhes de implementao da classe Form1. Portanto,
precisamos colocar um mtodo que adiciona uma nova conta na interface de uso da classe Form1.
public partial class Form1
{
// Esse o mesmo array que colocamos no captulo de arrays.
private Conta[] contas;
// outros mtodos de Form1
Captulo - Cadastro de novas contas - - Pgina
Material do Treinamento C e Orientao a Objetos
public void AdicionaConta(Conta conta) {
// implementao do mtodo adiciona conta
}
}
Inicialmente, temos zero contas cadastradas no sistema e a primeira conta ser colocada na posio zero,
no cadastro da segunda, temos conta j cadastrada e a prxima ser colocada na posio . Repare que
sempre colocamos a conta na posio equivalente ao nmero de contas que j esto cadastradas. Ento
para implementarmos o AdicionaConta, precisaremos de um novo atributo no formulrio que representa o
nmero de contas que j foram cadastradas.
public partial class Form1
{
private Conta[] contas;
// guarda o nmero de contas que j foram cadastradas
private int numeroDeContas;
// outros mtodos de Form1
public void AdicionaConta(Conta conta) {
this.contas[this.numeroDeContas] = conta;
this.numeroDeContas++;
}
}
Alm de colocar a conta no array, precisamos tambm registrar a conta no comboContas.
public void AdicionaConta(Conta conta) {
this.contas[this.numeroDeContas] = conta;
this.numeroDeContas++;
comboContas.Items.Add("titular: " + conta.Titular.Nome);
}
Precisamos utilizar esse novo mtodo dentro do formulrio de cadastro para cadastrar a nova conta:
private void botaoCadastro_Click(object sender, EventArgs e)
{
Conta novaConta = new ContaCorrente();
novaConta.Titular = new Cliente(textoTitular.Text);
novaConta.Numero = Convert.ToInt32(textoNumero.Text);
this.formPrincipal.AdicionaConta(novaConta);
}
Captulo - Cadastro de novas contas - - Pgina
Material do Treinamento C e Orientao a Objetos
Agora que temos toda a lgica pronta, precisamos apenas colocar umboto no formulrio principal que abre
o formulrio de cadastro de nova conta. Cham-lo-emos de botaoNovaConta:
Na ao desse boto, precisamos instanciar o FormCadastroConta passando a instncia do formulrio prin-
cipal. D um duplo clique no boto que acabamos de incluir no formulrio para implementar sua ao:
private void botaoNovaConta_Click(object sender, EventArgs e)
{
// this representa a instncia de Form1 que est sendo utilizada pelo
// Windows Form
FormCadastroConta formularioDeCadastro = new FormCadastroConta(this);
}
Para mostrar o formulrio, utilizaremos o mtodo ShowDialog do FormCadastroConta
private void botaoNovaConta_Click(object sender, EventArgs e)
{
FormCadastroConta formularioDeCadastro = new FormCadastroConta(this);
formularioDeCadastro.ShowDialog();
}
Com isso terminamos o cadastro de novas contas na aplicao.
. U1:t:znNoo o Ao:c:oNnCoN1n No tono oo vonmctKn:o
Temos o seguinte cdigo no mtodo que executado no Load do formulrio principal:
Captulo - Cadastro de novas contas - Utilizando o AdicionaConta no load do formulrio - Pgina
Material do Treinamento C e Orientao a Objetos
private void Form1_Load(object sender, EventArgs e)
{
this.contas = new Conta[3];
// vamos inicializar algumas instncias de Conta.
this.contas[0] = new Conta();
this.contas[0].Titular = new Cliente("victor");
this.contas[0].Numero = 1;
this.contas[1] = new ContaPoupanca();
this.contas[1].Titular = new Cliente("mauricio");
this.contas[1].Numero = 2;
this.contas[2] = new ContaCorrente();
this.contas[2].Titular = new Cliente("osni");
this.contas[2].Numero = 3;
foreach(Conta conta in contas)
{
comboContas.Items.Add(c.Titular.Nome);
}
}
Veja que estamos colocando as contas diretamente na posio correta do array, mas no estamos atualizando
o atributo numeroDeContas que inclumos no formulrio. Alm disso, inicializamos o array com apenas
posies, logo no temos mais espao para cadastrar as novas contas.
Para resolver o segundo problema, precisamos simplesmente modifcar o tamanho do array que alocado
para, por exemplo, aceitar at dez contas:
private void Form1_Load(object sender, EventArgs e)
{
this.contas = new Conta[10];
// resto do cdigo do mtodo
}
Para resolver o primeiro problema, o de atualizar o valor do atributo numeroDeContas, precisamos apenas de
um incremento depois de adicionar cada uma das contas no array:
private void Form1_Load(object sender, EventArgs e)
{
this.contas = new Conta[10];
// vamos inicializar algumas instncias de Conta.
Captulo - Cadastro de novas contas - Utilizando o AdicionaConta no load do formulrio - Pgina
Material do Treinamento C e Orientao a Objetos
this.contas[0] = new Conta();
this.contas[0].Titular = new Cliente("victor");
this.contas[0].Numero = 1;
this.numeroDeContas++;
this.contas[1] = new ContaPoupanca();
this.contas[1].Titular = new Cliente("mauricio");
this.contas[1].Numero = 2;
this.numeroDeContas++;
this.contas[2] = new ContaCorrente();
this.contas[2].Titular = new Cliente("osni");
this.contas[2].Numero = 3;
this.numeroDeContas++;
foreach(Conta conta in contas)
{
comboContas.Items.Add(c.Titular.Nome);
}
}
Veja que no cdigo do mtodo estamos cadastrando a conta no array, incrementando o nmero de contas e,
por fm, adicionando a conta no comboContas. Esse cdigo faz exatamente o mesmo trabalho que o mtodo
AdicionaConta que criamos nesse captulo. Ento, podemos reutiliz-lo:
private void Form1_Load(object sender, EventArgs e)
{
this.contas = new Conta[10];
// vamos inicializar algumas instncias de Conta.
Conta c1 = new Conta();
c1.Titular = new Cliente("victor")
c1.Numero = 1;
this.AdicionaConta(c1);
Conta c2 = new ContaPoupanca();
c2.Titular = new Cliente("mauricio");
c2.Numero = 2;
this.AdicionaConta(c2);
Conta c3 = new ContaCorrente();
c3.Titular = new Cliente("osni");
c3.Numero = 3;
this.AdicionaConta(c3);
}
Captulo - Cadastro de novas contas - Utilizando o AdicionaConta no load do formulrio - Pgina
Material do Treinamento C e Orientao a Objetos
Repare que com esse cdigo o mtodo Form1_Load no precisa mais se preocupar com os detalhes de como
as contas so armazenadas e nem de como adicionar a conta no comboContas. Todo esse conhecimento fca
encapsulado no mtodo AdicionaConta.
. Exvncc:os
) Vamos criar um novo formulrio que ser responsvel por fazer o cadastro de novas contas na aplicao.
Na janela do Solution Explorer, clique com o boto direito no nome do projeto e escolha a opo Add >
New Item.
Na janela de novo item, escolha a opo Windows Form e utilize FormCadastroConta como nome do
novo formulrio que ser criado. Dentro desse formulrio, coloque dois campos de texto, um chamado
textoNumero e outro chamado textoTitular. Alm disso, adicione tambm um novo boto nesse for-
mulrio. Esse ser o boto que cadastrar a nova conta. Chame o boto de botaoCadastro.
) Vamos agora implementar a ao do boto de cadastro desse novo formulrio (o FormCadastroConta).
D um duplo clique no boto que acabamos de adicionar. Dentro da ao do boto, leia as informaes
que foram digitadas no formulrio e utilize-as para criar uma nova ContaCorrente:
private void botaoCadastro_Click(object sender, EventArgs e)
{
ContaCorrente novaConta = new ContaCorrente();
novaConta.Titular = new Cliente(textoTitular.Text);
novaConta.Numero = Convert.ToInt32(textoNumero.Text);
}
Agora localize o construtor do FormCadastroConta:
public FormCadastroConta()
{
InitializeComponent();
}
Faa com que esse construtor receba um argumento do tipo Form1 chamado formPrincipal. Guarde o
valor que foi passado dentro de um novo atributo. Seu cdigo deve fcar parecido com o que segue:
public partial class FormCadastroConta : Form
{
private Form1 formPrincipal;
public CadastroDeConta(Form1 formPrincipal)
{
this.formPrincipal = formPrincipal;
InitializeComponent();
}
Captulo - Cadastro de novas contas - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
private void botaoCadastro_Click(object sender, EventArgs e)
{
ContaCorrente novaConta = new ContaCorrente();
novaConta.Titular = new Cliente(textoTitular.Text);
novaConta.Numero = Convert.ToInt32(textoNumero.Text);
}
}
) Dentro da classe do formulrio principal, arquivo Form1.cs, adicione um novo atributo chamado
numeroDeContas e um novo mtodo chamado AdicionaConta que receber uma conta como argumento
e a cadastrar no array de contas do formulrio:
public partial class Form1 : Form
{
private int numeroDeContas;
// Esse array j estava declarado na classe
private Conta[] contas;
// implementao das aes do formulrio
public void AdicionaConta(Conta conta)
{
this.contas[this.numeroDeContas] = conta;
this.numeroDeContas++;
comboContas.Items.Add("titular: " + conta.Titular.Nome);
}
}
) Abra novamente o cdigo do boto do formulrio de cadastro de novas contas. Dentro do mtodo
botaoCadastro_Click, utilize o AdicionaConta do formPrincipal passando a conta que foi criada ante-
riormente.
private void botaoCadastro_Click(object sender, EventArgs e)
{
ContaCorrente novaConta = new ContaCorrente();
novaConta.Titular = new Cliente(textoTitular.Text);
novaConta.Numero = Convert.ToInt32(textoNumero.Text);
this.formPrincipal.AdicionaConta(novaConta);
}
) Dentro do formulrio principal da aplicao (Form1.cs), coloque um novo boto que quando clicado
mostrar o formulrio de cadastro. Chame esse novo boto botaoNovaConta.
private void botaoNovaConta_Click(object sender, EventArgs e)
{
Captulo - Cadastro de novas contas - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
FormCadastroConta formularioCadastro = new FormCadastroConta(this);
formularioCadastro.ShowDialog();
}
) Antes de testar o cadastro de contas que acabamos de implementar, abra o mtodo Form1_Load do formu-
lrio principal e cadastre as contas padro do sistema utilizando o mtodo AdicionaConta que criamos
em um exerccio anterior:
private void Form1_Load(object sender, EventArgs e)
{
this.contas = new Conta[10];
// vamos inicializar algumas instncias de Conta.
Conta c1 = new Conta();
c1.Titular = new Cliente("victor")
c1.Numero = 1;
this.AdicionaConta(c1);
Conta c2 = new ContaPoupanca();
c2.Titular = new Cliente("mauricio");
c2.Numero = 2;
this.AdicionaConta(c2);
Conta c3 = new ContaCorrente();
c3.Titular = new Cliente("osni");
c3.Numero = 3;
this.AdicionaConta(c3);
}
Depois de fazer essa modifcao fnal, execute a aplicao e teste o cadastro.
) (Opcional) No formulrio de cadastro, adicione um combo box (chamado comboTipoConta) que permita
a escolha do tipo de conta que ser cadastrado.
) (Desafo) No projeto estamos atualmente utilizando um array de contas com um tamanho fxo e por isso
s podemos cadastrar um nmero limitado de contas. Modifque o mtodo AdicionaConta da classe
Form1 para que ele aceite um nmero ilimitado de contas.
Captulo - Cadastro de novas contas - Exerccios - Pgina
C
Classes abstratas
Emnosso banco os clientes podemter dois tipos de conta at o momento: conta corrente ou conta poupana.
Para instanciar estes tipos de conta, poderamos usar o seguinte cdigo:
//Instanciar uma nova conta corrente
ContaCorrente contaCorrente = new ContaCorrente();
//Instancia uma nova conta poupana
ContaPoupanca contaPoupanca = new ContaPoupanca();
Nos captulos anteriores, aprendemos que essas duas classes tm muito em comum, ambas so contas. No
apenas tm atributos em comum, mas tambm comportamentos. Para evitar a repetio do cdigo em
ambas as classes, vimos como isolar este cdigo repetido em uma classe Conta, e fazer com que as classes
ContaCorrente e ContaPoupanca herdem dessa classe me todo o cdigo em comum.
Alm da reutilizao de cdigo, tambm vimos a possibilidade de escrever mtodos que podem receber
argumentos tanto do tipo ContaCorrente quanto do tipo ContaPoupanca, utilizando polimorfsmo. Basta
fazermos os mtodos referenciarem o tipo mais genrico, no caso, Conta:
public class TotalizadorDeContas
{
// ...
public void Soma(Conta conta)
{
// ...
}
}
Mas o que acontece quando executamos a seguinte linha:
Material do Treinamento C e Orientao a Objetos
Conta c = new Conta();
Criamos um novo objeto do tipo Conta. Mas esse objeto faz algum sentido para nossas regras de negcio?
uma conta genrica, no sendo nem conta corrente e nem poupana.
Neste caso, no deveramos permitir a instanciao de objetos Conta.
Conta apenas uma ideia em nosso domnio, uma forma genrica de referenciarmos os dois tipos de conta
que realmente existem em nosso sistema, ContaCorrente e ContaPoupanca. Podemos evitar a criao de
objetos do tipo Conta defnindo a classe como abstrata:
public abstract class Conta
{
// ...
}
Desta forma, no podemos mais criar objetos do tipo Conta, mas podemos ainda usar variveis do tipo conta,
para referenciar objetos de outros tipos:
Conta conta = new Conta(); //no compila, no pode criar objetos abstratos
Conta cc = new ContaCorrente(); // pode, objeto do tipo ContaCorrente
Conta cp = new ContaPoupanca(); // pode, objeto do tipo ContaPoupanca
Repare que o calculo necessrio para realizar um saque diferente em cada um dos tipos de Conta. Sabemos
que uma conta deve ter um mtodo Saca, mas a implementao deste mtodo depende de regras especfcas
de cada tipo diferente de conta emnosso sistema. Uma soluo possvel seria implement-lo semfazer nada,
mas dizendo que ele pode ser sobrescrito (virtual):
public abstract class Conta
{
public virtual void Saca(double valor){
//no faz nada
}
// ...
}
E manter o cdigo Saca original nas classes flhas, dizendo que eles sobrescrevem (override) o mtodo na
classe pai:
public class ContaCorrente : Conta
{
public override void Saca(double valor)
Captulo - Classes abstratas - - Pgina
Material do Treinamento C e Orientao a Objetos
{
this.Saldo -= (valor + 0.10);
}
// ...
}
public class ContaPoupanca : Conta
{
public override void Saca(double valor)
{
this.Saldo -= valor;
}
// ...
}
Desejamos que toda classe flha implemente sua prpria verso do mtodo, com o comportamento referente
ao tipo da conta. Mas se esquecermos de sobrescrever o mtodo Saca em uma subclasse, o mtodo herdado
da classe Conta ser executado, que no faz nada. No queremos isso! Queremos obrigar as classes flha a
implementar o mtodo Saca.
Podemos obrigar todas as classes flhas a sobrescreverem um mtodo na classe me, basta declarar esse m-
todo com o modifcador abstract ao invs de virtual. Toda vez que marcamos um mtodo com o modif-
cador abstract, ele obrigatoriamente no pode ter uma implementao padro:
public abstract class Conta // marcando que a classe est incompleta
{
public abstract void Saca(double valor); // marcando que o mtodo est incompleto
}
Com essa modifcao, o mtodo Saca passa a representar apenas uma ideia, que precisa de uma imple-
mentao concreta nas classes flhas. Caso no implementemos esse mtodo na classe flha, o compilador
emitir umerro, avisando da obrigatoriedade de sobrescrever este mtodo. Ento se implementssemos, por
exemplo, a classe ContaPoupanca sem defnir a implementao do Saca, o cdigo da classe no compilar:
public class ContaPoupanca : Conta
{
// Essa classe no compila pois no colocamos a implementao para o Saca
}
Podemos ter uma classe abstrata sem nenhum mtodo abstrato, mas no o contrrio. Se a classe tem pelo
menos um mtodo abstrato, ela deve ser abstrata tambm pois como o mtodo est incompleto, a classe no
est completa.
Captulo - Classes abstratas - - Pgina
Material do Treinamento C e Orientao a Objetos
. Exvncc:os
) Transforme a classe Conta em uma classe abstrata. Repare que agora teremos um erro de compilao em
todos os pontos do cdigo em que tentamos instanciar o tipo Conta. Por qu? Modifque o cdigo da
sua aplicao para que a conta no seja instanciada, assim corrigiremos os erros de compilao. No se
esquea de sempre testar o seu cdigo.
) Repare que herdamos os mtodos Saca e Deposita da classe Conta, pormcada tipo de Conta sobrescreve
esses mtodos, logo eles so bons candidatos para mtodos abstratos. Transforme os mtodos Saca e
Deposita em mtodos abstratos, repare que com isso todas as classes flhas so obrigadas a dar uma
implementao para esses mtodos.
Captulo - Classes abstratas - Exerccios - Pgina
C
Interfaces
Nosso banco agora suporta Contas de Investimento. J sabemos como fazer: basta herdar da classe Conta:
public class ContaInvestimento : Conta
{
// comportamentos especficos da conta investimento
}
Por lei, uma vez por ano devemos pagar um tributo ao governo relacionado s contas de investimento e
contas de poupana. O mesmo no acontece com uma simples Conta Corrente.
Para resolver esse problema, podemos criar ummtodo emambas as classes que calcula o valor desse tributo.
Por exemplo:
public class ContaPoupanca : Conta
{
// outros metodos
public double CalculaTributo() {
return this.Saldo * 0.02;
}
}
public class ContaInvestimento : Conta
{
// outros metodos
public double CalculaTributo() {
return this.Saldo * 0.03;
}
}
Material do Treinamento C e Orientao a Objetos
Excelente. Os mtodos s fcam nas Contas que realmente sofrem esse tributo.
Agora, a prxima funcionalidade a gerao de um relatrio, no qual devemos imprimir a quantidade total
de tributos pagos por todas as Contas Investimento ou Poupanca do nosso banco. Precisamos de uma classe
que acumula o valor de todos os tributos de todas as contas do banco. Esse um problema parecido com o
que j tivemos antes:
public class TotalizadorDeTributos {
public double Total { get; private set; }
public void Acumula(ContaPoupanca cp) {
Total += cp.CalculaTributo();
}
public void Acumula(ContaInvestimento ci) {
Total += ci.CalculaTributo();
}
}
Pronto. Agora basta passarmos ContaInvestimento ou ContaPoupanca e nossa classe acumular o valor do
tributo. Repare que toda vez que uma nova conta sofrer um tributo, precisaremos lembrar de voltar na classe
TotalizadorDeTributos e criar um novo mtodo Acumula().
Nos captulos anteriores, resolvemos isso usando polimorfsmo. Se a classe pai possuir o mtodo emcomum,
ento basta recebermos uma referncia pro tipo pai:
public class TotalizadorDeTributos {
public double Total { get; private set; }
public void Acumula(Conta c) {
Total += c.CalculaTributo();
}
}
Mas ser que faz sentido colocar o mtodo CalculaTributo() na classe Conta?
public abstract class Conta {
// resto da classe aqui
public abstract double CalculaTributo();
}
Nem todas as Contas so tributveis. Se fzermos isso, a classe ContaCorrente ganhar esse mtodo, mas ela
no sofre tributo!
Captulo - Interfaces - - Pgina
Material do Treinamento C e Orientao a Objetos
Precisamos achar uma maneira de achar um pai em comum apenas para a ContaCorrente e
ContaInvestimento. Classes em C no podem ter dois pais. Mas o que podemos fazer dizer para o
compilador que garantiremos a existncia do mtodo CalculaTributo() nas classes que chegarem para o
mtodo Acumula().
Como fazemos isso? Simples. Fazemos a classe assinar um contrato! Nesse caso, queremos assinar o
contrato que fala que somos Tributveis. Contratos no C so conhecidos como interfaces. A declarao de
uma interface praticamente igual a de uma classe, pormutilizamos a palavra interface ao invs de class.
public interface Tributavel
{
// cdigo da interface
}
A conveno de nomes do C para uma interface seguir a mesma conveno de nomenclatura de classes
porm com um I no comeo do nome:
public interface ITributavel
{
}
uma boa prtica colocar o cdigo da interface dentro de um arquivo separado com o mesmo nome da
interface. Por exemplo, a interface ITributavel fcaria no arquivo ITributavel.cs. Dentro da interface,
queremos colocar a declarao do mtodo CalculaTributo(). Mtodos declarados em uma interface nunca
possuem implementao e sempre so pblicos. A declarao da interface ITributavel com o mtodo
CalculaTributo() fca da seguinte forma:
// Arquivo ITributavel.cs
public interface ITributavel
{
double CalculaTributo();
}
Queremos fazer com que a conta poupana assine o contrato ITributavel que acabamos de criar, para isso,
precisamos colocar o nome da interface que queremos implementar logo aps a declarao da classe pai:
// Arquivo ContaPoupanca.cs
public class ContaPoupanca : Conta, ITributavel
{
// Implementao dos mtodos da ContaPoupanca
}
Captulo - Interfaces - - Pgina
Material do Treinamento C e Orientao a Objetos
Como a interface ITributavel declara o mtodo CalculaTributo(), toda classe que assina a interface
obrigada a dar uma implementao para essa funcionalidade, se no implementarmos o mtodo da interface,
a classe no compilar.
public class ContaPoupanca : Conta, ITributavel
{
// resto da classe aqui
// mtodo que sou obrigado a implementar
public double CalculaTributo()
{
return this.Saldo * 0.02;
}
}
Repare que, para implementarmos o mtodo da interface, no podemos utilizar a palavra override, ela
reservada para a sobrescrita de mtodos da Herana. A mesma coisa para a ContaInvestimento:
public class ContaInvestimento : Conta, ITributavel
{
// resto da classe aqui
// mtodo que sou obrigado a implementar
public double CalculaTributo()
{
return this.Saldo * 0.03;
}
}
Almdisso, podemos fazer comque uma classe assine uma interface semherdar de outra classe. Por exemplo,
o banco tambm trabalha com seguros de vida que tambm so tributveis, logo podemos representar essa
classe com o seguinte cdigo:
public class SeguroDeVida : ITributavel
{
public double CalculaTributo()
{
// implementao do CalculaTributo
}
}
Dessa forma, podemos dizer que a classe TotalizadorDeTributos recebe um ITributavel qualquer. O
polimorfsmo funciona com interfaces!
Captulo - Interfaces - - Pgina
Material do Treinamento C e Orientao a Objetos
public class TotalizadorDeTributos {
public double Total { get; private set; }
public void Acumula(ITributavel t) {
Total += t.CalculaTributo();
}
}
Excelente! Veja que com interfaces conseguimos fazer com que um conjunto de classes implemente os mes-
mos mtodos.
Interfaces so bem mais simples do que classes. Elas no tem atributos e seus mtodos no tem implemen-
tao. A interface apenas nos garante que o mtodo existir naquela classe. Por esse motivo, apesar de C
no suportar herana mltipla (ser flho de mais de uma classe), podemos implementar quantas interfaces
quisermos. Basta colocar uma na frente da outra:
public class ContaInvestimento : Conta, ITributavel, OutraInterfaceQualquer
{
// implementa os mtodos das interfaces Tributavel e OutraInterfaceQualquer
}
Quando uma classe utiliza tanto herana quanto interfaces, precisamos sempre declarar qual a classe pai e
depois as interfaces, assim como fzemos na ContaPoupanca:
// Repare que primeiro colocamos a classe pai (Conta) e depois as interfaces.
// Se mudarmos a ordem, o cdigo no compilar.
public class ContaPoupanca : Conta, ITributavel
{
// implementao
}
Acostume-se com interfaces. Daqui pra frente, veremos as vrias interfaces que existem no C!
. Exvncc:os
) O banco precisa gerenciar os impostos que sero pagos por seus produtos. Para resolver esse problema,
criaremos uma nova interface chamada ITributavel. Para criar a interface, clique como boto direito do
mouse no nome do projeto e escolha a opo Add > New Item (o mesmo que utilizamos para criar o for-
mulrio de cadastro). Na janela de novo item, escolha a opo Interface e coloque o nome ITributavel:
Captulo - Interfaces - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Faa com que essa interface declare um mtodo chamado CalculaTributos que no recebe nenhum
argumento e devolve um double que representa o valor do imposto que deve ser pago.
O cdigo da interface deve fcar parecido com o seguinte:
public interface ITributavel
{
double CalculaTributos();
}
) O que acontece se tentarmos instanciar uma interface?
ITributavel t = new ITributavel();
Erro de compilao. Interfaces no tem implementao e, logo, no podem ser instanciadas.
O cdigo compila, mas o objeto no faz nada.
O C busca aleatoriamente uma classe que implementa essa interface e a instancia.
) Faa comque a classe ContaCorrente implemente a interface ITributavel que acabamos de criar, porm
ainda no implemente o mtodo CalculaTributos. Tente executar o cdigo. O que aconteceu?
) Como a ContaCorrente assina a interface ITributavel, precisamos colocar uma implementao para
o mtodo CalculaTributos dentro da classe, se no o cdigo do projeto no compilar. Implemente o
mtodo CalculaTributos da ContaCorrente, faa comque a ContaCorrente pague de seu saldo como
imposto.
) Crie uma nova classe no banco chamada SeguroDeVida e faa com que essa classe implemente a interface
ITributavel. O mtodo CalculaTributos do SeguroDeVida deve devolver um valor constante de
reais.
Captulo - Interfaces - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) Agora vamos adicionar um novo boto no formulrio que calcular os impostos do banco. Chame-o de
botaoImpostos. No cdigo desse boto, teste o mtodo CalculaTributos em diferentes situaes, por
exemplo:
private void botaoImpostos_Click(object sender, EventArgs e)
{
ContaCorrente conta = new ContaCorrente();
conta.Deposita(200.0);
MessageBox.Show("imposto da conta corrente = " + conta.CalculaTributos());
ITributavel t = conta;
MessageBox.Show("imposto da conta pela interface = " + t.CalculaTributos());
SeguroDeVida sv = new SeguroDeVida();
MessageBox.Show("imposto do seguro = " + sv.CalculaTributos());
t = sv;
MessageBox.Show("imposto do seguro pela interface" + t.CalculaTributos());
}
Depois de implementar seus testes, tente clicar no boto para ver o que acontece.
) (Opcional) Crie uma nova classe chamada TotalizadorDeTributos, que ser responsvel por acumular
os impostos de diferentes produtos tributveis do banco:
public class TotalizadorDeTributos
{
public double Total { get; private set; }
public void Adiciona(ITributavel t)
{
this.Total += t.CalculaTributos();
}
}
Depois de criar essa classe, modifque o cdigo do boto do exerccio passado para que ele utilize a classe
que acabamos de criar para calcular o total de impostos. Por exemplo:
private void botaoImpostos_Click(object sender, EventArgs e)
{
ContaCorrente conta = new ContaCorrente();
conta.Deposita(200.0);
SeguroDeVida sv = new SeguroDeVida();
TotalizadorDeTributos totalizador = new TotalizadorDeTributos();
Captulo - Interfaces - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
totalizador.Adiciona(conta);
MessageBox.Show("Total: " + totalizador.Total);
totalizador.Adiciona(sv);
MessageBox.Show("Total: " + totalizador.Total);
}
) (Desafo) Pesquise sobre a palavra is do C no seguinte link http://msdn.microsof.com/en-us/library/
scektxw.aspx e depois tente modifcar o cdigo o boto para que ele seja capaz de calcular automatica-
mente o imposto de todas as contas correntes que esto cadastradas no array de contas da aplicao.
Captulo - Interfaces - Exerccios - Pgina
C
Mtodos e atributos estticos
Precisamos agora guardar a quantidade de contas corrente existentes no sistema. Uma das maneiras de fazer
isso gerenciar o total de contas e adicionar unidade nesse total toda vez que criarmos uma nova conta:
int totalDeContasCorrente = 0;
// ...
ContaCorrente novaConta = new ContaCorrente();
totalDeContasCorrente++;
Contudo, utilizando essa abordagem, um desenvolvedor pode esquecer de alterar a varivel
totalDeContasCorrente aps criar uma nova ContaCorrente, gerando um erro no sistema. Para evi-
tar isso, seria melhor que a prpria classe controlasse o total de contas criadas. Uma primeira ideia seria
guardar um atributo com o total de contas criadas na classe e, no seu prprio construtor, adicionar uma
unidade nesse atributo:
public class ContaCorrente : Conta
{
// Outros atributos da classe
private int totalDeContas = 0;
public ContaCorrente()
{
this.totalDeContas++;
}
// Mtodos da classe
}
Material do Treinamento C e Orientao a Objetos
Qual seria o valor do atributo totalDeContas se fossem criadas duas contas?
ContaCorrente primeira = new ContaCorrente();
ContaCorrente segunda = new ContaCorrente();
Ambas as contas apresentariam o valor no seu atributo totalDeContas. Isso acontece porque o atributo
totalDeContas diferente para cada objeto que instanciamos, isto , o atributo pertence a cada objeto.
O que desejamos que que tivssemos um atributo compartilhado em todos os objetos da classe, ou seja,
que o atributo pertena classe ao invs dos objetos.
Estes atributos recebem o nome de atributos da classe ou atributos estticos e, em C, para criar um atributo
esttico basta colocar a palavra static na declarao do atributo:
public class ContaCorrente : Conta
{
private static int totalDeContas = 0;
// resto do cdigo existente
}
Com isso, o nosso construtor fcaria:
public class ContaCorrente : Conta
{
private static int totalDeContas = 0;
public ContaCorrente
{
ContaCorrente.totalDeContas++;
}
// resto do cdigo existente
}
O prximo passo criar um controle que mostra qual o nmero da prxima conta disponvel, isto , o total
de contas mais um. Com isso, criaramos um mtodo pblico que devolva o totalDeContas + 1:
public class ContaCorrente : Conta
{
private static int totalDeContas = 0;
public ContaCorrente
{
ContaCorrente.totalDeContas++;
}
public int ProximaConta()
{
Captulo - Mtodos e atributos estticos - - Pgina
Material do Treinamento C e Orientao a Objetos
return ContaCorrente.totalDeContas + 1;
}
// resto do cdigo existente
}
Mas como o mtodo pertence ao objeto (no esttico) e no classe, temos que instanciar uma conta para
poder acess-lo:
// aqui o total 0, imprimiria 1, que desejamos
ContaCorrente conta = new ContaCorrente();
conta.ProximaConta(); // imprime 2, pois j criamos uma
Perceba que precisamos criar um novo objeto para chamar o mtodo ProximaConta. Mas, ao criar uma nova
conta, o valor do totalDeContas j foi alterado. Para evitar isso, o mtodo precisa pertencer classe ao
invs do objeto. De maneira semelhante a um atributo esttico, colocando a palavra static ao declarar um
mtodo, este se torna esttico:
public class ContaCorrente : Conta
{
// resto do cdigo existente
public static int ProximaConta()
{
return ContaCorrente.totalDeContas + 1;
}
}
E para usar esse novo mtodo:
int proxima = ContaCorrente.ProximaConta();
. Exvncc:os Ovc:oNn:s
) No cadastro de contas, estamos pedindo o nmero que ser cadastrado na nova conta, mas em nosso
banco, duas contas no podem ter o mesmo nmero. Para garantirmos que o nmero das contas ser
nico, podemos utilizar o static do C para criar umcontador de instncias de contas que foramcriadas.
Declare na classe conta um novo atributo esttico chamado numeroDeContas que contar quantas contas
foram criadas na aplicao. Adicione um construtor na class Conta que no recebe nenhum argumento e
gera o Numero utilizando o valor do atributo esttico numeroDeContas:
Captulo - Mtodos e atributos estticos - Exerccios Opcionais - Pgina
Material do Treinamento C e Orientao a Objetos
public abstract class Conta
{
private static int numeroDeContas;
public Conta()
{
Conta.numeroDeContas++;
this.Numero = Conta.numeroDeContas;
}
// Resto da classe continua igual
}
) Abra o formulrio de cadastro de novas contas. Procure no cdigo desse formulrio a ao do boto que
cadastra a nova conta utilizando os dados digitados pelo usurio, mtodo botaoCadastro_Click. Dentro
desse mtodo, apague a linha que atribui o nmero da conta que ser criada. Esse nmero agora gerado
pela prpria classe conta.
) Agora que a conta gera seu nmero, no mais possvel para o usurio saber qual ser o nmero da conta
que ser cadastrada. Para resolvermos esse problema, vamos mostrar qual ser o nmero da prxima
conta no campo textoNumero do formulrio de cadastro.
O numeroDeContas um atributo esttico e privado dentro da classe Conta, logo o formulrio no pode
acessar o valor desse atributo para mostr-lo. Crie um novo mtodo esttico na classe Conta chamado
ProximoNumero que ser responsvel por devolver o nmero da prxima Conta que ser criada pela apli-
cao.
) Agora vamos fazer o formulrio de cadastro mostrar o nmero da prxima conta para o usurio.
D um duplo clique no formulrio de cadastro para fazer com que o Visual Studio crie o mtodo
que ser executado no load do formulrio. Dentro desse mtodo, mostre o resultado do mtodo
Conta.ProximoNumero() no campo textoNumero.
private void FormCadastroConta_Load(object sender, EventArgs e)
{
textoNumero.Text = Convert.ToString(Conta.ProximoNumero());
}
. Pnnn snnvn mn:s ctnssvs vs1K1:cns
Algumas vezes criamos classes que contmapenas mtodos auxiliares estticos. Como essas classes no pos-
suem mtodos nem propriedades de instncias, no queremos permitir que elas sejam instanciadas. Nessas
situaes, podemos utilizar as classes estticas do C. Para criar uma classe esttica, precisamos apenas uti-
lizar a palavra static em sua declarao:
Captulo - Mtodos e atributos estticos - Para saber mais classes estticas - Pgina
Material do Treinamento C e Orientao a Objetos
public static class Funes
{
// implementao
}
Quando uma classe declarada como esttica, ela no pode ser instanciada e nem herdada e, portanto, s
pode possuir membros estticos.
public static class Funcoes
{
// Esse mtodo vlido dentro de uma classe esttica.
public static bool MetodoEstatico()
{
// implementao
}
// Esse mtodo no vlido dentro de uma classe esttica.
public bool MetodoInstancia()
{
// implementao
}
}
Captulo - Mtodos e atributos estticos - Para saber mais classes estticas - Pgina
C
Excees
Voltando nossa classe ContaPoupanca, umdos seus mtodos o Saca. Se tentarmos sacar umvalor superior
ao saldo do cliente, o mtodo no permitir o saque. Contudo, quemchamou o mtodo no saber se o saque
foi realizado ou no. Como notifcar quem invocou o mtodo que o saque foi feito com sucesso ou no?
. Rv1onNo oo mv1ooo vnnn coN1notnn vnnos
Uma primeira soluo seria alterar o mtodo Saca para retornar um booleano indicando se o saque foi ou
no efetuado:
public class ContaPoupanca : Conta
{
public override bool Saca(double valor)
{
if (valor + 0.10 <= this.Saldo)
{
this.Saldo -= valor + 0.10;
return true;
}
else
{
return false;
}
}
// Resto do cdigo da classe
}
Assim, podemos saber se o saque foi efetuado ao chamar o mtodo:
Material do Treinamento C e Orientao a Objetos
Conta conta = new ContaPoupanca();
// Inicializa a conta
if (conta.Saca(100.0))
{
MessageBox.Show("Saque efetuado");
}
Essa abordagem importante, por exemplo, no caso de um caixa eletrnico. Ns precisamos saber se o
saque foi efetuado ou no antes de liberarmos o dinheiro para o cliente. Contudo, uma desvantagem dessa
abordagem que, se esquecermos de testar o retorno do mtodo Saca, podemos liberar dinheiro para o
cliente sem permisso.
E mesmo invocando o mtodo e tratando o seu retorno de maneira adequada, o que faramos se fosse ne-
cessrio sinalizar exatamente qual foi o tipo de erro que aconteceu, como quando o usurio passou um valor
negativo como quantidade?
Uma soluo seria alterar o retorno de boolean para nmero inteiro e retornar o cdigo do erro que ocorreu.
Isso considerado uma m prtica, pois o valor devolvido mgico e s legvel perante extensa documenta-
o (magic numbers), alm de no obrigar o programador a tratar esse retorno, o que pode levar o programa
a continuar executando em um estado inconsistente.
Um outro problema aconteceria se o mtodo j retornasse algum valor. Desse jeito, no daria para alterar o
retorno para indicar se o saque foi realizado ou no.
. CoN1notnNoo vnnos comvxcvovs
Para evitar esses problemas, o C nos permite tratar essas excees regra de uma maneira diferente: atravs
de exceptions. Em vez de retornarmos um valor dizendo se uma operao foi bem sucedida, ns lanamos
uma exceo regra padro, ao comportamento padro, dizendo que algo de errado aconteceu. No nosso
caso, utilizaremos a exceo Exception, indicando que houve um erro na operao de saque:
public class ContaPoupanca : Conta
{
public override void Saca (double valor)
{
if (valor + 0.10 > this.saldo)
{
throw new Exception("Valor do saque maior que o saldo");
}
else
{
this.saldo -= valor + 0.10;
}
Captulo - Excees - Controlando erros com excees - Pgina
Material do Treinamento C e Orientao a Objetos
}
}
At o momento, aprendemos como lanar uma exception quando algum comportamento ocorreu de forma
fora do comum. Mas, o que essa exception infuencia na classe que o chamou? Por exemplo, vamos ver o que
acontece quando tentamos sacar um valor superior ao saldo do cliente. Rode a sua aplicao com F5 e tente
sacar um valor superior ao saldo de um cliente.
Ao clicar no boto de saque, a execuo do cdigo ser interrompida na linha emque a exceo lanada. Isso
ocorre porque o F roda o nosso programa em modo debug. Se rodarmos o programa fora do modo debug
comCtrl+F5, como se fosse umusurio rodando o programa, veramos uma janela dizendo que ocorreu um
erro:
Mas, ns no queremos que o usurio receba tal mensagemna tela. Ento, no podemos chamar diretamente
um mtodo que pode lanar uma exceo. Ao invs disso, devemos tentar chamar o mtodo: se no for
lanada nenhuma exceo, ok; caso contrrio, devemos pegar a exceo e executar um trecho de cdigo
referente exceo.
Para tentar executar um trecho de cdigo que pode lanar uma exceo, devemos coloc-lo dentro de um
bloco try. No nosso caso, colocaremos dentro do bloco que trata o clique do boto saque:
private void botaoSaque_Click(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
double valor = Convert.ToDouble(textoValor.Text);
Conta selecionada = this.contas[indice];
try
{
selecionada.Saca(valor);
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
MessageBox.Show("Dinheiro Liberado");
}
}
E para pegar a exceo caso seja lanada e trat-la, devemos pr o cdigo dentro de um block catch:
Captulo - Excees - Controlando erros com excees - Pgina
Material do Treinamento C e Orientao a Objetos
private void botaoSaque_Click(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
double valor = Convert.ToDouble(textoValor.Text);
Conta selecionada = this.contas[indice];
try
{
selecionada.Saca(valor);
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
MessageBox.Show("Dinheiro Liberado");
}
catch (Exception ex)
{
MessageBox.Show("Saldo insuficiente");
}
}
Nesse bloco, caso o mtodo Saca lance uma exceo, o bloco catch ser executado mostrando a mensagem
Saldo Insuficiente. No caso de uma exceo, a mensagem Dinheiro Liberado no exibida.
. Tnn1nNoo mt1:vtns vxcvovs
Uma outra situao exceptional ocorre quando o usurio da classe Conta tenta sacar um valor negativo,
claramente um valor invlido para o saque. Nesse caso tambm queremos lanar uma exceo:
public override void Saca (double valor)
{
if(valor < 0.0)
{
throw new Exception();
}
if (valor + 0.10 > this.Saldo)
{
throw new Exception("Valor do saque maior que o saldo");
}
else
{
this.saldo -= valor + 0.10;
}
}
Quando passamos um valor negativo para o mtodo Saca, o mtodo lanar uma Exception, portanto o
cdigo do bloco catch do caixa eletrnico ser executado para tratar a exceo gerada, exibindo para o
usurio a mensagem Saldo Insuficiente. Porm essa mensagem est claramente errada.
Captulo - Excees - Tratando mltiplas excees - Pgina
Material do Treinamento C e Orientao a Objetos
Repare que, para jogarmos a exceo, precisamos executar um new, ou seja, a Exception uma classe do
C! Podemos criar uma hierarquia de excees utilizando a herana para indicar qual foi o tipo de erro que
ocorreu.
Para criarmos um novo tipo de exceo, precisamos apenas criar uma nova classe que herde de
Exception. Vamos criar uma exceo que indica que ocorreu um erro por saldo insufciente na conta, a
SaldoInsuficienteException:
public class SaldoInsuficienteException : Exception
{
}
E vamos utilizar o SaldoInsuficienteException no mtodo Saca da classe ContaPoupanca:
public override void Saca (double valor)
{
if(valor < 0.0)
{
throw new Exception();
}
if (valor + 0.10 > this.Saldo)
{
throw new SaldoInsuficienteException();
}
else
{
this.saldo -= valor + 0.10;
}
}
Quando o usurio passa um argumento negativo ainda lanamos uma exceo genrica. Podemos criar
um novo tipo de exceo que indica que o argumento passado invlido. Porm, o C j possui um con-
junto de excees padro na linguagem (http://msdn.microsof.com/pt-br/library/system.exception.aspx
inheritanceContinued) . Dentre essas excees, existe a ArgumentException, que indica que o argumento de
um mtodo invlido. Vamos utilizar essa exceo no nosso cdigo:
public override void Saca (double valor)
{
if(valor < 0.0)
{
throw new ArgumentException();
}
if (valor + 0.10 > this.Saldo)
{
Captulo - Excees - Tratando mltiplas excees - Pgina
Material do Treinamento C e Orientao a Objetos
throw new SaldoInsuficienteException();
}
else
{
this.saldo -= valor + 0.10;
}
}
Agora o cdigo do caixa eletrnico pode tratar de forma diferente cada um dos tipos de exceo:
private void botaoSaque_Click(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
double valor = Convert.ToDouble(textoValor.Text);
Conta selecionada = this.contas[indice];
try
{
selecionada.Saca(valor);
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
MessageBox.Show("Dinheiro Liberado");
}
catch (SaldoInsuficienteException ex)
{
MessageBox.Show("Saldo insuficiente");
}
catch (ArgumentException ex)
{
MessageBox.Show("No possvel sacar um valor negativo");
}
}
Mas o que deve ser colocado dentro de um bloco try? Ser que devemos colocar apenas a execuo do
mtodo que lana a exceo?
private void botaoSaque_Click(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
double valor = Convert.ToDouble(textoValor.Text);
Conta selecionada = this.contas[indice];
try
{
selecionada.Saca(valor);
}
catch (SaldoInsuficienteException ex)
{
Captulo - Excees - Tratando mltiplas excees - Pgina
Material do Treinamento C e Orientao a Objetos
MessageBox.Show("Saldo insuficiente");
}
catch (ArgumentException ex)
{
MessageBox.Show("No possvel sacar um valor negativo");
}
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
MessageBox.Show("Dinheiro Liberado");
}
Ao executar o cdigo, vemos que o mtodo Saca lana a exceo de saldo insufciente. Mas, mesmo assim, o
caixa libera dinheiro para o usurio. Isso acontece porque a exceo lanada no mtodo Saca j foi tratada
nos blocos catch e a execuo do programa continua normalmente.
O bloco try deve conter toda a lgica de negcio que ser executada em uma situao normal, quando no
ocorrem casos excepcionais. Assim, podemos nos preocupar apenas com a lgica de negcios e depois nos
preocupamos com os erros que aconteceram.
No caso do saque, queremos executar o mtodo Saca e depois emitir o dinheiro dentro do bloco try.
private void botaoSaque_Click(object sender, EventArgs e)
{
int indice = comboContas.SelectedIndex;
double valor = Convert.ToDouble(textoValor.Text);
Conta selecionada = this.contas[indice];
try
{
selecionada.Saca(valor);
textoSaldo.Text = Convert.ToString(selecionada.Saldo);
MessageBox.Show("Dinheiro Liberado");
}
catch (SaldoInsuficienteException ex)
{
MessageBox.Show("Saldo insuficiente");
}
catch (ArgumentException ex)
{
MessageBox.Show("No possvel sacar um valor negativo");
}
}
Veja que o tratamento dos erros fcou totalmente isolado da lgica de negcios. Utilizando excees, pode-
mos nos preocupar apenas com a lgica de negcio do sistema e s depois com o tratamento de erros. No
existe mistura de cdigo!
Captulo - Excees - Tratando mltiplas excees - Pgina
Material do Treinamento C e Orientao a Objetos
. Exvncc:os
) Quais das opes a seguir representa o lanamento de uma nova exceo em nosso sistema?
throw new Exception();
return Exception();
return new Exception();
throw Exception();
) Analise o cdigo a seguir e assinale a alternativa correta:
var conta = new Conta();
var caixa = new Caixa();
conta.Deposita(100.0);
conta.Saca(500.0);
caixa.Libera(500.0);
Se a linha lanar uma exceo, a linha no ser executada.
A ltima linha no ser executada mesmo se o cdigo no lanar excees.
Se a linha lanar uma exceo, nenhuma das linhas ser executada.
Todas as linhas so executadas mesmo quando alguma delas lana uma exceo.
) Onde devemos colocar um trecho de cdigo que pode lanar uma exceo para quando queremos trat-
la?
Dentro de um bloco try
Dentro de um bloco catch
No precisa estar em nenhum bloco em especfco.
) Onde devemos colocar o cdigo que trata uma exceo?
Dentro de um bloco catch
Dentro de um bloco try
No precisa estar em nenhum bloco em especfco.
) Modifque o mtodo Deposita da classe ContaPoupanca para que ele lance um ArgumentException
quando o argumento passado para o mtodo for negativo. O seu mtodo deve fcar parecido com o
seguinte:
public class ContaPoupanca : Conta
{
// resto do cdigo da ContaPoupanca
Captulo - Excees - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
public override void Deposita(double valor)
{
if(valor < 0.0)
{
throw new ArgumentException();
}
// resto do mtodo continua igual
}
}
Depois de fazer essa modifcao, execute a aplicao e tente depositar um valor negativo em uma conta
poupana e veja o que acontece.
) Agora utilize um try/catch na ao do boto que realiza um depsito, botaoDeposito_Click da classe
Form1, para tratar a exceo que pode ser lanada pelo Deposita. Quando o Deposita lanar uma exceo,
mostre um MessageBox com a mensagem "Argumento Invlido".
) (Opcional) Vamos agora criar uma nova exceo chamada SaldoInsuficienteException que ser lan-
ada toda vez que tentarmos sacar um valor que superior ao saldo atual da conta. Essa classe deve
simplesmente herdar da classe Exception do C:
public class SaldoInsuficienteException : Exception { }
Agora modifque o mtodo Saca da classe ContaPoupanca para que ele jogue a
SaldoInsuficienteException toda vez que o usurio tentar sacar um valor maior do que o saldo
da conta.
Modifque tambm o mtodo botaoSaque_Click para que ele mostre a mensagem "Saldo
Insuficiente" caso o mtodo Saca lance a exceo SaldoInsuficienteException.
) (Opcional) Faa as mesmas modifcaes para a ContaCorrente.
) (Opcional) Um outro bloco que existe o finally. Pesquise sobre ele em http://msdn.microsof.com/
pt-br/library/fkttz( v=vs.).aspx e diga quando um cdigo dentro de um bloco fnally executado.
Sempre
S se uma exceo for lanada.
Nunca
S se nenhuma exceo for lanada
Captulo - Excees - Exerccios - Pgina
C
Namespaces
Como crescimento do sistema, passamos a ter diversas classes nele. Por exemplo, as que envolvemo modelo
de nosso sistema como as classes ligadas a conta:
public abstract class Conta
{
// Implementao da classe Conta
}
public class ContaCorrente : Conta
{
// Implementao da classe ContaCorrente
}
public class ContaPoupanca : Conta
{
// Implementao da classe ContaPoupanca
}
As classes voltadas ao relacionamento com o cliente:
public class Cliente
{
// Implementao da classe Cliente
}
public class Gerente
{
// Implementao da classe Gerente
}
Material do Treinamento C e Orientao a Objetos
As classes ligadas aos emprstimos feitos pelo cliente:
public class Credito
{
// Implementao da classe Credito
}
public class CreditoImobiliario : Credito
{
// Implementao da classe CreditoImobiliario
}
E as classes referentes aos investimentos:
public class Fundo
{
// Implementao da classe Fundo
}
public class CDB
{
// Implementao da classe CDB
}
O grande problema que surge com os sistemas grandes a organizao de todas as suas classes. Para evitar
que o sistema fque catico, podemos agrupar as classes por caractersticas comuns e dar umnome para cada
umdesses grupos. Isto , agruparamos umconjunto de classes emumespao emcomume lhe daramos um
nome, como por exemplo Caelum.Banco.Investimentos. Esse espao defnido por um nome chamado de
namespace.
Segundo a conveno de nomes adotada pela Microsof(http://msdn.microsof.com/en-us/library/ke.
aspx) , os namespaces devem ter a forma: NomeDaEmpresa.NomeDoProjeto.ModuloDoSistema.
No nosso caso, os namespaces fcariam da seguinte forma:
namespace Caelum.Banco.Usuarios
{
public class Cliente
{
// Implementao da classe Cliente
}
}
Captulo - Namespaces - - Pgina
Material do Treinamento C e Orientao a Objetos
namespace Caelum.Banco.Usuarios
{
public class Gerente
{
// Implementao da classe Gerente
}
}
namespace Caelum.Banco.Investimentos
{
public class Fundo
{
// Implementao da classe Fundo
}
}
namespace Caelum.Banco.Investimentos
{
public class CDB
{
// Implementao da classe CDB
}
}
Antes de realizar essa separao de nossas classes em namespaces, elas estavam no mesmo namespace: o
namespace do nome do projeto. Assim, para defnir o cliente referente a um investimento precisaramos
apenas criar um novo atributo na classe Investimento: private Cliente cliente.
Contudo, com o uso dos namespaces, a classe Cliente no est mais no mesmo namespace da classe
Investimento. Para poder referenciar qualquer uma das quatro classes anteriores devemos indicar o seu
namespace:
Caelum.Banco.Usuarios.Gerente guilherme =
new Caelum.Banco.Usuarios.Gerente();
Caelum.Banco.Usuarios.Cliente mauricio =
new Caelum.Banco.Usuarios.Cliente();
Caelum.Banco.Investimentos.Fundo acoes =
new Caelum.Banco.Investimentos.Fundo();
Caelum.Banco.Investimentos.CDB cdb =
new Caelum.Banco.Investimentos.CDB();
O nome completo de uma classe agora envolve adicionar uma referncia ao namespace dela. Por isso, deixa-
mos de acessar Gerente diretamente e passamos a acessar Caelum.Banco.Usuarios.Gerente.
Umexemplo de cdigo j existente na plataforma C que usa namespaces envolve imprimir uma nica linha
no console usando o mtodo WriteLine de System.Console:
Captulo - Namespaces - - Pgina
Material do Treinamento C e Orientao a Objetos
System.Console.WriteLine("Minha conta bancaria");
Note como o uso de namespaces para organizar suas classes acaba implicando em mais cdigo na hora de
utilizar as mesmas. Por isso, podemos criar atalhos ao dizer que usaremos as classes que pertencem a um
namespace. Por exemplo, podemos citar que usaremos o namespace System e, a partir de ento, podemos
escrever nosso cdigo como se tudo o que est dentro do namespace System estivesse no mesmo namespace
em que estamos:
using System;
Console.WriteLine("Minha conta bancaria");
Podemos tambm usar vrios namespaces dentro do mesmo arquivo:
using System;
using Caelum.Banco.Usuarios;
Console.WriteLine("Minha Conta Bancaria");
Cliente cliente = new Cliente();
A utilizao da palavra chave using permite notifcar ao compilador que usaremos classes daquele names-
pace. Com isso, obtemos a vantagem da organizao do cdigo atravs de namespace e continuamos com
um cdigo enxuto.
. Pnnn snnvn mn:s - DvctnnnXo ov Nnmvsvncv nN:Nnnoos
No C, podemos criar um namespace dentro de outro namespace j existente. Por exemplo:
namespace Caelum.Banco
{
// dentro do namespace Caelum.Banco
// agora podemos criar um namespace aninhado
namespace Contas
{
// o nome desse namespace Caelum.Banco.Contas
}
}
O namespace Contas do cdigo acima tambm poderia ser declarado da seguinte forma:
Captulo - Namespaces - Para saber mais - Declarao de namespace aninhados - Pgina
Material do Treinamento C e Orientao a Objetos
namespace Caelum.Banco.Contas
{
// tambm declara o namespace Caelum.Banco.Contas
}
Para a linguagem C, as duas declaraes so equivalentes.
. Pnnn snnvn mn:s - At:ns vnnn Nnmvsvncvs
Em aplicaes grandes, podemos ter namespaces com nomes muito grandes, por exemplo:
namespace Caelum.Banco.Produtos.Contas
{
public abstract class Conta
{
// Implementao
}
}
Vimos que, no cdigo C, podemos utilizar o using para no digitarmos o nome completo da classe toda
vez que ela for utilizada, mas o que aconteceria se tivssemos outra classe chamada Conta? Por exemplo, o
banco tem um sistema de autenticao e a classe que guarda informaes sobre o usurio chamada Conta:
namespace Caelum.Banco.Seguranca
{
public class Conta
{
// Implementao
}
}
Claramente, as classes so diferentes pois possuem namespaces diferentes, mas no cdigo que as utiliza, no
podemos importar as duas classes pois o compilador do C no saber qual das duas estamos utilizando.
using Caelum.Banco.Produtos.Contas;
using Caelum.Banco.Seguranca;
namespace Banco.Sistema
{
public class ControleAutenticacao
{
// Conta do usurio ou Conta do banco?
Captulo - Namespaces - Para saber mais - Alias para namespaces - Pgina
Material do Treinamento C e Orientao a Objetos
public void Autentica(Conta conta)
{
// implementao
}
}
}
Nessa situao, precisamos escolher qual o namespace que vamos importar. Se colocarmos um using para
Caelum.Banco.Produtos.Contas, por exemplo, para utilizarmos a Conta do usurio precisamos do nome
completo da classe, Caelum.Banco.Seguranca.Conta, um nome bem grande. Nessa situao, podemos dar
um apelido (alias) menor para um namespace do C com a palavra using:
using Caelum.Banco.Produtos.Contas;
using SegurancaDoBanco = Caelum.Banco.Seguranca;
namespace Banco.Sistema
{
public class ControleAutenticacao
{
// Conta a do namespace Caelum.Banco.Produtos.Conta
// para usarmos a conta do usurio fazemos:
// SegurancaDoBanco.Conta
public void Autentica(SegurancaDoBanco.Conta contaUsuario)
{
// implementao
}
}
}
Podemos tambm defnir um alias para uma classe do namespace:
using Caelum.Banco.Produtos.Contas;
using ContaDoUsuario = Caelum.Banco.Seguranca.Conta;
namespace Banco.Sistema
{
public class ControleAutenticacao
{
// Conta a do namespace Caelum.Banco.Produtos.Conta
// para usarmos a conta do usurio, utilizamos ContaDoUsuario
public void Autentica(ContaDoUsuario conta)
{
// implementao
}
Captulo - Namespaces - Para saber mais - Alias para namespaces - Pgina
Material do Treinamento C e Orientao a Objetos
}
}
. Exvncc:os
) Como instanciar a classe Conta a seguir, que est dentro de um namespace?
namespace Caelum.Banco {
public class Conta {
// classe aqui
}
}
new Conta();
new Conta.Caelum.Banco();
new Conta() in Caelum.Banco;
new Caelum.Banco.Conta();
) Como importar a classe a seguir, usando using?
namespace Caelum.Banco
{
public abstract class Conta
{
// codigo aqui
}
}
using Caelum;
using Caelum.Banco;
using Caelum.Banco.Conta;
) Faa com que o namespace das contas da aplicao seja Banco.Contas, por exemplo, para a classe Conta,
teramos:
// arquivo Conta.cs
namespace Banco.Contas
{
public class Conta
{
// implementao da classe Conta
}
}
Captulo - Namespaces - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Depois de fazermos essa modifcao, as classes que utilizam a conta tero que import-la com o using
do C. No formulrio principal da aplicao, classe Form1, por exemplo, teramos:
using Banco.Contas;
namespace Banco
{
public class Form1 : Form
{
// implementao do formulrio
}
}
Repare que o namespace completamente separado da estrutura de pastas do projeto, ou seja, podemos
organizar os arquivos do projeto da forma que desejarmos.
) (Opcional) Mesmo que a estrutura de diretrios seja completamente separada do namespace, sempre
bom defnirmos regras para a estrutura de pastas do projeto. Uma estrutura muito utilizada no .Net
colocar todas as classes de um determinado namespace dentro de um diretrio com o mesmo nome do
namespace. Para as contas da aplicao, por exemplo, teramos a seguinte estrutura:
Vamos mover os arquivos do projeto para seguirmos essa estrutura. Dentro do projeto Banco, crie uma
nova pasta chamada Contas e dentro dessa pasta coloque todas as contas do sistema. Veja que podemos
mover livremente os arquivos sem quebrar o cdigo da aplicao.
Captulo - Namespaces - Exerccios - Pgina
C
Classe Object
Emcaptulos anteriores vimos a utilizao do polimorfsmo para referenciar mais de umtipo de classe, como
o caso das classes ContaCorrente e ContaPoupanca. Ambas podemser referenciadas como objetos da classe
Conta.
Mas ser que Conta herda de algum? E se herdar, todas as outras classes tambm herdariam. Isto , uma
classe que representa a base para todos os objetos do sistema... uma classe Object. O cdigo a seguir o
mesmo que a defnio antiga de Conta:
public abstract class Conta : Object
{
// cdigo
}
desnecessrio dizermos que Conta herda de Object. como se o prprio compilador fzesse o cdigo
anterior ao digitarmos:
public abstract class Conta
{
// cdigo
}
Assim, podemos dizer que toda classe em C um Object. Uma vez que Conta Object, ContaCorrente e
ContaPoupanca passam a ser Object indiretamente.
Material do Treinamento C e Orientao a Objetos
. ImvtvmvN1nNoo n comvnnnXo ov on)v1os
Vimos no primeiro captulo sobre orientao a objetos que quando fazemos uma comparao de duas vari-
veis do tipo Conta, o que comparamos na realidade so as referncias que esto armazenadas nas variveis:
Conta c1 = new ContaCorrente();
c1.Numero = 1;
Conta c2 = new ContaCorrente();
c2.Numero = 1;
if(c1 == c2)
{
MessageBox.Show("iguais");
}
else
{
MessageBox.Show("diferentes");
}
Nesse cdigo, as duas contas criadas guardamexatamente as mesmas informaes, pormcomo c1 e c2 guar-
damreferncias, quando fazemos c1 == c2, estamos comparando a referncia da varivel c1 coma referncia
da varivel c2 e, como elas apontam para objetos diferentes, o cdigo mostra a mensagem "diferentes".
Para corrigir esse problema, precisamos comparar os valores das propriedades da conta ao invs do valor das
variveis c1 e c2. Por exemplo, no sistema que desenvolvemos, duas contas so consideradas iguais apenas
quando seus nmeros so iguais, ento o cdigo da comparao deveria fcar da seguinte forma:
if(c1.Numero == c2.Numero)
{
MessageBox.Show("iguais");
}
else
{
MessageBox.Show("diferentes");
}
Portanto, emtodos os pontos do sistema emque precisamos comparar dois objetos do tipo conta, precisamos
repetir o if acima. Mas o que aconteceria se precisssemos mudar a regra de comparao de duas contas?
Nesse caso teramos que buscar todas as comparaes de contas da aplicao e atualizar a regra, o que pode
ser muito trabalhoso.
Para resolver o problema da comparao de objetos, a Microsof introduziu na classe Object um mtodo
especializado em fazer a comparao de dois objetos, o mtodo Equals. Como em toda herana a classe
Captulo - Classe Object - Implementando a comparao de objetos - Pgina
Material do Treinamento C e Orientao a Objetos
flha ganha os comportamentos da classe pai, podemos utilizar o Equals para fazer a comparao entre dois
objetos:
if(c1.Equals(c2))
{
MessageBox.Show("iguais");
}
else
{
MessageBox.Show("diferentes");
}
Porm, ao executarmos o cdigo, a aplicao ainda mostra a mensagem "diferentes". Isso ocorre porque
a implementao padro do Equals que vem herdada da classe Object faz a comparao das referncias, ou
seja, o if do cdigo anterior ainda faz a comparao c1 == c2.
Podemos mudar o comportamento padro do mtodo Equals herdado da classe Object utilizando a sobres-
crita:
public abstract class Conta
{
// outras propriedades e mtodos
// Nesse mtodo implementamos a regra de igualdade entre duas contas
public override bool Equals (Object outro)
{
// Implementao da igualdade de contas.
}
}
Repare que o mtodo Equals recebe umargumento do tipo Object, ento podemos utiliz-lo para comparar
uma conta com qualquer valor do C.
Dentro da implementao do mtodo Equals, queremos implementar a regra de igualdade entre contas
duas contas so iguais se os seus nmeros forem iguais:
public abstract class Conta
{
// outras propriedades e mtodos
// Nesse mtodo implementamos a regra de igualdade entre duas contas
public override bool Equals (Object outro)
{
return this.Numero == outro.Numero;
}
}
Captulo - Classe Object - Implementando a comparao de objetos - Pgina
Material do Treinamento C e Orientao a Objetos
Porm, repare que a varivel outro do tipo Object, que no possui uma propriedade chamada Numero,
apenas a Conta possui essa propriedade. Ento, antes de fazermos a comparao precisamos converter a
varivel outro para o tipo Conta utilizando o cast:
public abstract class Conta
{
// outras propriedades e mtodos
// Nesse mtodo implementamos a regra de igualdade entre duas contas
public override bool Equals (Object outro)
{
Conta outraConta = (Conta) outro;
return this.Numero == outraConta.Numero;
}
}
Depois de colocarmos essa implementao do mtodo Equals na classe Conta, podemos tentar executar
novamente a comparao de contas:
if(c1.Equals(c2))
{
MessageBox.Show("iguais");
}
else
{
MessageBox.Show("diferentes");
}
Dessa vez, o C utilizar a implementao do Equals que colocamos dentro da classe Conta, fazendo a com-
parao pelos nmeros. Portanto, teremos a mensagem "iguais".
. MvtnonnNoo n :mvtvmvN1nXo oo Eqcnts como :s
Repare que o mtodo Equals recebe o tipo Object. Sendo assim, podemos comparar a conta com qualquer
outro objeto do sistema, por exemplo, a string:
Conta c = new ContaCorrente();
if(c.Equals("Mensagem"))
E na implementao do Equals, fazemos o cast do argumento passado para o tipo Conta, porm a string
no uma conta. Como o cast invlido, o C lana uma exceo do tipo InvalidCastException. Para
evitarmos essa exceo precisamos verifcar que o argumento do Equals realmente do tipo Conta antes de
fazermos a operao de cast. Para fazer esse trabalho, podemos utilizar o operador is do C:
Captulo - Classe Object - Melhorando a implementao do Equals com o is - Pgina
Material do Treinamento C e Orientao a Objetos
public override bool Equals(Object outro)
{
if(outro is Conta)
{
// outro do tipo Conta, ento podemos fazer o cast
}
}
Nesse cdigo, se a varivel outro guardar uma referncia para um objeto que do tipo Conta (instncia de
Conta ou classe flha), o is devolve true, se no ele devolve false.
Se outro no for uma Conta, ento o mtodo deveria devolver false, do contrrio ele deve fazer o cast e
comparar os nmeros. Assim, o Equals pode ser implementado com o seguinte cdigo:
public override bool Equals(Object outro)
{
// Se no temos um objeto do tipo Conta
// Ento o mtodo devolve false
if(!(outro is Conta))
{
return false
}
Conta outraConta = (Conta) outro;
return this.Numero == outraConta.Numero;
}
. IN1vcnnNoo o On)vc1 como ComnoBox
Nos captulos anteriores modifcamos o formulrio do Banco para utilizar um combo box para fazer a orga-
nizao das contas cadastradas. Para colocarmos um novo item no cambo box, utilizamos o mtodo Add em
sua propriedade Items passando qual o novo texto que queremos adicionar:
comboContas.Items.Add("NovoItem");
Com isso, o combo box mostrar um novo item com o texto "NovoItem". Na verdade, quando utilizamos
esse mtodo Add, podemos passar qualquer objeto como argumento:
Conta c = new ContaCorrente();
c.Numero = 1;
comboContas.Items.Add(c);
Captulo - Classe Object - Integrando o Object com o ComboBox - Pgina
Material do Treinamento C e Orientao a Objetos
Quando passamos um objeto para o mtodo Add, o C precisa transformar esse objeto em uma string que
ser exibida como item do combo box. Para isso ele utiliza mais um mtodo herdado da classe Object
chamado ToString. A responsabilidade desse mtodo transformar um objeto qualquer em uma string.
A implementao padro do mtodo ToString que vem herdado da classe Object simplesmente devolve a
string que representa o nome completo da classe, ou seja, nome do namespace seguido do nome da classe
(Banco.Contas.ContaCorrente, no caso da ContaCorrente). Mas, para mostrarmos a conta no combo box,
precisamos de uma implementao que descreva a conta que o usurio est selecionando, ento vamos no-
vamente utilizar a sobrescrita de mtodos para modifcar o comportamento do ToString:
public abstract class Conta
{
// outros mtodos e propriedades
public override string ToString()
{
}
}
Dentro desse mtodo ToString, precisamos devolver um texto que descreva a conta que o usurio est sele-
cionando:
public abstract class Conta
{
// outros mtodos e propriedades
public Cliente Titular { get; set; }
public override string ToString()
{
return "titular: " + this.Titular.Nome;
}
}
Agora que colocamos a implementao do ToString na classe Conta, ao executarmos novamente o cdigo
que adiciona um item no combo box, o C mostrar o resultado do ToString que foi implementado.
. Exvncc:os
) Assinale a alternativa correta
Todas as classes em C herdam diretamente ou indiretamente de Object
Captulo - Classe Object - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Object uma classe abstrata
S as classes que no herdam de nenhuma classe so herdadas de Object
Object uma interface
) Analise o cdigo a seguir e diga qual ser a sua sada.
class Cliente
{
public string Nome { get; set; }
public string Rg { get; set; }
public Cliente(string nome)
{
this.Nome = nome;
}
public override bool Equals(Object obj)
{
Cliente outroCliente = (Cliente) obj;
return this.Nome == outroCliente.Nome && this.Rg == outroCliente.Rg;
}
}
Cliente guilherme = new Cliente("Guilherme Silveira");
guilherme.Rg = "12345678-9";
Cliente mauricio = new Cliente("Mauricio Aniche");
mauricio.Rg = "12345678-9";
if (guilherme.Equals(mauricio))
{
MessageBox.Show("So o mesmo cliente");
}
else
{
MessageBox.Show("No so o mesmo cliente");
}
No so o mesmo cliente
O cdigo no compila
So o mesmo cliente
Nada mostrado
O cdigo roda mas quebra ao executar
) Vamos sobrescrever o mtodo ToString da classe Conta com a seguinte implementao:
Captulo - Classe Object - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
public abstract class Conta
{
// Resto da implementao da Conta
public override String ToString()
{
return "titular: " + this.Titular.Nome;
}
}
Agora adicionaremos a conta ao invs de uma string como item do combo box dentro do mtodo
AdicionaConta do formulrio principal da aplicao, classe Form1:
public void AdicionaConta(Conta conta)
{
this.contas[this.numeroDeContas] = conta;
this.numeroDeContas++;
comboContas.Items.Add(conta);
}
Depois de fazer essa modifcao, teste a aplicao e veja o ToString da conta em ao dentro dos opes
do combo box.
) Quando adicionamos um objeto no combo box, mais interessante recuperar diretamente o objeto que
foi selecionado do que o ndice que foi selecionado.
Para recuperar o objeto que est selecionado emumcombo box, utilizamos a propriedade SelectedItem.
Essa propriedade devolve um Object que guarda a instncia selecionada no combo box.
Sabendo disso, podemos modifcar a ao do boto de depsito, botaoDeposito_Click da classe Form1,
para utilizar o SelectedItem do comboContas, que conter a instncia da conta que o usurio selecionou
na interface grfca. Porm para podermos utilizar a conta selecionada, precisamos primeiro convert-la
para uma instncia de Conta:
private void botaoDeposito_Click(object sender, EventArgs e)
{
Conta selecionada = (Conta) comboContas.SelectedItem;
// implementa a lgica de depsito utilizando a conta
}
Implemente e teste essa modifcao dentro do seu projeto. Faa o mesmo para o boto de saque.
) (Opcional) Em algumas situaes no queremos utilizar o ToString do prprio objeto para montar a
lista de itens do combo box, nessas situaes, podemos utilizar uma propriedade do ComboBox chamada
DisplayMember para escolher qual a propriedade do objeto que queremos incluir como item do combo.
Por exemplo, no seguinte cdigo, os items do combo box sero e :
Conta c = new ContaCorrente() { Numero = 1 };
Conta c2 = new ContaCorrente() { Numero = 2 };
Captulo - Classe Object - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
comboContas.Items.Add(c);
comboContas.Items.Add(c2);
comboContas.DisplayMember = "Numero";
Quando utilizamos o DisplayMember o combo box tambm utiliza o ToString do membro para montar
o item que ser exibido para o usurio.
Utilize o DisplayMember para mostrar o ToString da propriedade Titular da conta ao invs de mostrar
o ToString da prpria Conta.
Captulo - Classe Object - Exerccios - Pgina
C
Trabalhando com listas
Se quisermos armazenar muitas contas na memria, podemos fazer o uso de arrays, o qual j estudamos nos
captulos anteriores. Arrays nos possibilitam guardar uma quantidade de elementos e depois acess-los de
forma fcil.
Mas o problema que manipular um array no fcil. Por exemplo, imagine um array com contas guar-
dadas. Se quisermos remover a posio , como fazemos? Pois, se apagarmos, precisaremos reordenar todo
nosso array. E para inserir um elemento no meio do array? Precisamos abrir um buraco no array, empur-
rando elementos pra baixo, para a sim colocar o novo elemento no meio.
. Fnc:t:1nNoo o 1nnnntno comcotvovs n1nnvvs ons t:s1ns
Para resolver os problemas do array, podemos trabalhar com uma classe do C chamada List. Para utilizar-
mos uma lista dentro do cdigo precisamos informar qual o tipo de elemento que a lista armazenar:
Material do Treinamento C e Orientao a Objetos
// cria uma lista que armazena o tipo Conta
List<Conta> lista = new List<Conta>();
Da mesma forma que criamos a lista de contas, tambm poderamos criar uma lista de nmeros inteiros ou
de qualquer outro tipo do C. Essa lista do C armazena seus elementos dentro de um array.
Agora que instanciamos o List, podemos utilizar o mtodo Add para armazenar novos elementos:
Conta c1 = new ContaCorrente();
Conta c2 = new ContaPoupanca();
Conta c3 = new ContaCorrente();
// c1 fica na posio 0
lista.Add(c1);
// c2 na 1
lista.Add(c2);
// e c3 na 2
lista.Add(c3);
Se quisermos pegar essa Conta, podemos acess-la pela sua posio (no caso, , igual no array):
Conta conta = lista[0];
Se quisermos remover uma das contas da lista, podemos usar o mtodo Remove ou RemoveAt:
// A lista comea da seguinte forma: [c1, c2, c3]
// Depois do Remove, ela termina da seguinte forma: [c1, c3]
// A conta c1 continua na posio 0 e c3 vai para a posio 1
lista.Remove(c2); // remove pelo elemento
// Depois dessa chamada, c3 ocupa a posio 0: [c3]
lista.RemoveAt(0); // remove pelo ndice
Se quisermos saber quantos elementos existem em nosso List, podemos simplesmente ler a propriedade
Count:
var c1 = new ContaCorrente();
var c2 = new ContaInvestimento();
lista.Add(c1);
lista.Add(c2);
int qtdDeElementos = lista.Count;
Captulo - Trabalhando com listas - Facilitando o trabalho com colees atravs das listas - Pgina
Material do Treinamento C e Orientao a Objetos
Tambm podemos descobrir se um elemento est dentro de uma lista:
Conta c1 = new ContaCorrente();
Conta c2 = new ContaPoupanca();
lista.Add(c1);
bool temC1 = lista.Contains(c1); // true
bool temC2 = lista.Contains(c2); // false
Um outro recurso que a classe List nos fornece a iterao em cada um dos seus elementos:
Conta c1 = new ContaCorrente();
Conta c2 = new ContaPoupanca();
lista.Add(c1);
lista.Add(c2);
foreach (Conta c in lista)
{
MessageBox.Show(c.ToString());
}
Veja como lidar com colees de elementos fcou muito mais fcil com a classe List!
. Exvncc:os
) Como descobrimos a quantidade de elementos armazenado em um List?
var lista = new List<Conta>();
lista.Add(...);
lista.Add(...);
lista.Add(...);
lista.Size
lista.Count()
lista.Size()
lista.Count
lista.GetTotal()
) Qual o mtodo que remove um elemento da lista pela sua posio?
Captulo - Trabalhando com listas - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
lista.Remove(posicao);
lista.RemoveAt(posicao);
lista.DeleteFrom(posicao);
lista.DeleteAt(posicao);
) A classe List implementa uma interface mais genrica de listas. Qual ?
Voc pode consultar a documentao da classe no prprio site da Microsof: http://msdn.microsof.com/
pt-br/library/shey.aspx
IList
Nenhuma
List
GenericList
) Vamos modifcar o cdigo do projeto do banco para utilizar listas ao invs de arrays para guardar as contas
cadastradas.
Inicialmente substitua a declarao do atributo que guarda a referncia para o array de contas pela decla-
rao de uma lista de contas. Apague tambm a declarao do atributo numeroDeContas:
// Essa declarao ser utilizada no lugar do array
// de contas
private List<Conta> contas;
Modifque o mtodo Form1_Load para que ele instancie um List<Conta> ao invs de um array de contas:
private void Form1_Load(object sender, EventArgs e)
{
this.contas = new List<Conta>();
// o resto do mtodo continua igual
}
Por fm, modifcaremos o mtodo AdicionaConta do formulrio principal:
public void AdicionaConta(Conta conta) {
this.contas.Add(conta);
comboContas.Items.Add(conta);
}
Depois dessas modifcaes, teste a aplicao.
Captulo - Trabalhando com listas - Exerccios - Pgina
C
Lidando com conjuntos
Agora estamos interessados em melhorar o cadastro de contas que implementamos nos captulos anteriores.
O banco no quer aceitar o cadastro de contas cujo titular seja devedor, ento dentro do sistema precisamos
guardar uma lista com nomes dos devedores:
List<string> devedores = new List<string>();
devedores.Add("victor");
devedores.Add("osni");
Agora no cadastro precisamos verifcar se o nome que foi digitado no formulrio est dentro dessa lista.
Podemos fazer isso utilizando o mtodo Contains da classe List:
string titular = // l o campo titular do cadastro
bool ehDevedor = devedores.Contains(titular);
Mas a implementao do Contains da lista precisa percorrer todos os nomes cadastrados para s ento
devolver se o elemento est ou no dentro da lista. Dessa forma, dependendo do tamanho da lista, essa
busca pode fcar demorada.
. O1:m:znNoo n ncscn n1nnvvs ov coN)cN1os
Como vimos, as listas no so muito otimizadas para as operaes de buscas, pois alm de permitirem a
repetio de elementos (que prejudica o desempenho da busca), precisam percorrer todos os elementos para
implementarem a operao Contains.
Quando precisamos que a operao de busca seja rpida, utilizamos os conjuntos do C ao invs das listas.
Conjuntos so estruturas nas quais podemos fazer buscas rpidas e que no permitemrepetio de elementos.
Material do Treinamento C e Orientao a Objetos
Um dos tipos de conjuntos disponveis no C a classe HashSet. Para buscar de maneira rpida, o HashSet
categoriza os seus elementos, de forma a encontr-los rapidamente. Por exemplo, imagine voc em um
supermercado. Se voc quer comprar sorvete, voc no olha todos os itens do supermercado, mas sim vai
direto para a seo de congelados. L, voc procura o seu sorvete favorito. Veja que voc olhou muito menos
elementos, pois foi direto para a categoria dele. O HashSet faz a mesma coisa. Ele d categorias para cada
um dos elementos, e quando busca por eles, vai direto para a categoria.
Acategoria dada a partir do mtodo GetHashCode() que vemherdado da classe Object do C. Esse mtodo
devolve um nmero inteiro que representa qual a categoria do objeto.
Cc:onoos no sonnvscnvvvn o Gv1HnsnCoov
Quando sobrescrevemos o mtodo Equals de uma classe uma boa prtica tambm sobres-
crevermos o mtodo GetHashCode. Alm disso, para que o HashSet funcione corretamente, a
implementao do GetHashCode deve obedecer seguinte regra:
Se tivermos dois objetos, objeto1 e objeto2, comobjeto1.Equals(objeto2) devolvendo o valor
true, ento os mtodos GetHashCode do objeto1 e do objeto2 devem devolver o mesmo valor.
Ou seja, objetos iguais devem ser da mesma categoria.
Um detalhe interessante dos conjuntos que voc pode adicionar, remover e at mesmo verifcar se um
elemento est l. Mas diferentemente da lista, voc no consegue pegar um elemento randmico nela. Por
exemplo, conjunto[10] no funciona! E isso faz sentido: no existe ordem em um conjunto.
HashSet<string> devedores = new HashSet<string>();
// Podemos adicionar elementos no conjunto utilizando o mtodo Add
devedores.Add("victor");
devedores.Add("osni");
// Para sabermos o nmero de elementos adicionados, utilizamos a propriedade
// Count do conjunto. Nesse exemplo elementos guardar o valor 2
Captulo - Lidando com conjuntos - Otimizando a busca atravs de conjuntos - Pgina
Material do Treinamento C e Orientao a Objetos
int elementos = devedores.Count;
// O conjunto no guarda elementos repetidos, ento se tentarmos
// adicionar novamente a string "victor", o nmero de elementos
// continua sendo 2
devedores.Add("victor");
// Para perguntarmos se o conjunto possui um determinado elemento,
// utilizamos o mtodo Contains
bool contem = devedores.Contains("osni");
// No podemos pegar um elemento pela sua posio, pois os elementos do
// conjunto no possuem uma ordenao bem determinada. O cdigo abaixo
// gera um erro de compilao:
devedores[0];
Para iterarmos nos elementos de um HashSet, podemos utilizar novamente o comando foreach:
foreach(string devedor in devedores)
{
MessageBox.Show(devedor);
}
Quando executamos o foreach em um HashSet, a ordem em que os elementos so iterados indefnida.
. CoN)cN1os OnovNnoos como Son1voSv1
Em muitas aplicaes alm da busca rpida, tambm precisamos manter a ordenao dos elementos de um
conjunto. Nesse tipo de aplicao, podemos utilizar uma nova classe do C chamada SortedSet.
O SortedSet funciona de forma similar ao HashSet, utilizamos o Add para adicionar um elemento, o Remove
para remover itens, o Count para perguntar quantos elementos esto armazenados e Contains para verifcar
se um determinado elemento est no conjunto. A diferena que no HashSet os elementos so espalhados
em categorias e por isso no sabemos qual a ordem da iterao, j o SortedSet guarda os elementos na
ordem crescente. Ento no exemplo do conjunto de devedores, teramos um conjunto em que os elementos
esto em ordem alfabtica:
SortedSet<string> devedores = new SortedSet<string>();
devedores.Add("Hugo");
devedores.Add("Ettore");
devedores.Add("Osni");
devedores.Add("Alberto");
Captulo - Lidando com conjuntos - Conjuntos Ordenados com o SortedSet - Pgina
Material do Treinamento C e Orientao a Objetos
devedores.Add("Victor");
// Esse foreach vai mostrar os nomes na seguinte ordem:
// Alberto, Ettore, Hugo, Osni e por fim Victor
foreach(string nome in devedores)
{
MessageBox.Show(nome);
}
. A :N1vnvncv ov 1ooos os coN)cN1os
Vimos que temos duas classes que representam conjuntos no C, o HashSet e o SortedSet, em ambas as
classes, quando queremos armazenar um elemento utilizamos o mtodo Add, para remover o Remove, para
buscar o Contains e para saber o nmero de elementos o Count, por esse motivo, existe uma interface que
declara todos os comportamentos comuns aos conjunto que a interface ISet.
. ComvnnnXo vN1nv t:s1ns v coN)cN1os
Vimos que as listas e os conjuntos so duas estruturas que expem muitos mtodos em comum, mas que
tambm possuem diversas diferenas:
Nas listas os elementos so armazenados na ordem de insero enquanto cada conjunto armazena os
elementos na ordem que desejar para otimizar o tempo de busca;
Listas aceitam repeties enquanto os conjuntos no;
Podemos acessar elementos de uma lista atravs de seu ndice, uma operao que no faz sentido no
conjunto..
Como listas e conjuntos possuem muitas operaes em comum, tanto as listas quanto os conjuntos imple-
mentam uma outra interface do C chamada ICollection:
Captulo - Lidando com conjuntos - A interface de todos os conjuntos - Pgina
Material do Treinamento C e Orientao a Objetos
Alm disso, aprendemos que podemos utilizar o foreach com qualquer coleo do C. Isso acontece por-
que o foreach aceita qualquer classe que implemente a interface IEnumerable, que uma super interface
(interface pai) da ICollection:
. Exvncc:os
) Qual a sada do programa a seguir?
var conjunto = new HashSet<Conta>();
var c1 = new ContaCorrente();
conjunto.Add(c1);
Captulo - Lidando com conjuntos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
conjunto.Add(c1);
MessageBox.Show(conjunto.Count.ToString());


Um Set no possui propriedade Count

) Como eliminar todos os elementos de um conjunto?
var conjunto = new HashSet<Conta>();
conjunto.????();
.Clear()
.DeleteAll()
.Reset()
.Empty()
) No Banco, no podemos criar novas contas para clientes que so devedores, ento na tela de cadastro de
nova conta, antes de criarmos a nova conta que ser adicionada na aplicao precisamos verifcar se ela
est em uma lista de devedores que contm 30000 nomes.
Adicione no projeto uma nova pasta chamada Busca e dentro dessa pasta crie uma nova classe chamada
GeradorDeDevedores com o seguinte cdigo:
namespace Banco.Busca
{
public class GeradorDeDevedores
{
public List<string> GeraList()
{
List<string> nomes = new List<string>();
for(int i = 0; i < 30000; i++)
{
nomes.Add("devedor " + i);
}
return nomes;
}
}
}
Essa a classe que ser responsvel por gerar a lista de devedores que utilizaremos na aplicao.
No construtor do formulrio de cadastro, classe FormCadastroConta, vamos utilizar o
GeradorDeDevedores para inicializar a lista de devedores:
Captulo - Lidando com conjuntos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
public partial class FormCadastroConta : Form
{
private ICollection<string> devedores;
private Form1 formPrincipal;
public FormCadastroConta(Form1 formPrincipal)
{
this.formPrincipal = formPrincipal;
InitializeComponent();
GeradorDeDevedores gerador = new GeradorDeDevedores();
this.devedores = gerador.GeraList();
}
// Resto da classe continua igual
}
Agora na ao do boto de cadastro, antes de criarmos a conta, precisamos verifcar se o titular dessa nova
conta devedor:
private void botaoCadastro_Click(object sender, EventArgs e)
{
string titular = textoTitular.Text;
bool ehDevedor = this.devedores.Contains(titular);
if(!ehDevedor)
{
// faz a lgica para criar a conta
}
else
{
MessageBox.Show("devedor");
}
}
) Para verifcarmos a diferena entre o tempo de busca de listas e conjuntos, vamos repetir a busca 30000
vezes dentro de um loop:
private void botaoCadastro_Click(object sender, EventArgs e)
{
string titular = this.textoTitular.Text;
bool ehDevedor = false;
for(int i = 0; i < 30000; i++)
{
ehDevedor = this.devedores.Contains(titular);
}
if(!ehDevedor)
Captulo - Lidando com conjuntos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
{
// faz a lgica para criar a conta
}
else
{
MessageBox.Show("devedor");
}
}
Enquanto o cdigo est executando, tente mover a janela. O que aconteceu?
) Agora modifque o GeradorDeDevedores para que ele utilize um HashSet ao invs de um List:
public HashSet<string> GeraList()
{
HashSet<string> nomes = new HashSet<string>();
for(int i = 0; i < 30000; i++)
{
nomes.Add("devedor " + i);
}
return nomes;
}
Repare que, para utilizarmos o HashSet, precisamos mudar os tipos do objeto instanciado, da varivel
e do retorno no mtodo. O que podemos fazer para evitar tantas mudanas quando queremos trocar a
implementao de coleo que usamos?
) Teste novamente o cadastro da conta e veja que dessa vez a busca mais rpida.
) Experimente tambm outras colees no mtodo GeraList.
. Bcscns nKv:ons c1:t:znNoo D:c:oNKn:os
No projeto do banco, temos diversas contas cadastradas e agora queremos criar uma nova busca de conta
por nome do titular. Para implementar essa busca, podemos iterar na lista de contas e comparar o nome do
titular de cada uma dessas contas:
IList<Conta> contas = // pega as contas cadastradas
string titularDaBusca = "victor";
Conta resultado = null;
foreach(Conta conta in contas)
{
if(conta.Titular.Nome.Equals(titularDaBusca))
{
resultado = conta;
Captulo - Lidando com conjuntos - Buscas rpidas utilizando Dicionrios - Pgina
Material do Treinamento C e Orientao a Objetos
break;
}
}
Agora repare que em todo ponto do cdigo em que precisamos buscar uma conta pelo nome do titular,
precisamos repetir esse bloco de cdigo, alm disso, essa busca passa por todas as contas cadastradas no
sistema, o que pode demorar bastante. Para resolver esse problema de forma efciente, o C nos oferece os
Dicionrios (Dictionary).
O Dictionary uma classe que consegue associar uma chave a um valor. Utilizando o dicionrio, podemos,
por exemplo, associar o nome do titular com uma conta do sistema. Quando vamos construir um dicionrio
dentro do cdigo, precisamos informar qual o tipo da chave e qual ser o tipo do valor associado a essa
chave, para implementarmos a busca de contas, precisaramos de um dicionrio que associa uma chave do
tipo string com uma Conta.
Dictionary<String, Conta> dicionario = new Dictionary<String, Conta>();
Agora para colocarmos um valor no dicionrio, utilizamos o mtodo Add:
Dictionary<String, Conta> dicionario = new Dictionary<String, Conta>();
Conta conta = // inicializa a conta
// vamos adicionar a conta no dicionrio
// associa o nome do titular com a conta.
dicionario.Add(conta.Titular.Nome, conta);
Depois que inicializamos o dicionrio, podemos realizar buscas de valores utilizando as chaves que foram
cadastradas. Vamos, por exemplo, buscar a conta de um titular chamado "Victor":
Conta busca = dicionario["Victor"];
Veja que utilizando dicionrios a busca por nomes fcou muito mais simples do que a busca utilizando o
foreach, alm disso, as buscas com dicionrios so to rpidas quanto buscas utilizando conjuntos, ou seja,
muito mais efcientes do que o nosso foreach inicial.
. I1vnnNoo No o:c:oNKn:o
Alm de fazermos buscas rpidas, podemos tambm iterar nos elementos que esto armazenados, para isso
tambm utilizamos o foreach do C. Porm qual ser o tipo que utilizaremos dentro do foreach?
Ao iterarmos em um dicionrio, o tipo utilizado dentro do foreach um tipo que consegue guardar um
par de chave associado a um valor do dicionrio (KeyValuePair). Logo, no cdigo do foreach o tipo seria
KeyValuePair<tipo da chave, tipo do valor>:
Captulo - Lidando com conjuntos - Iterando no dicionrio - Pgina
Material do Treinamento C e Orientao a Objetos
Dictionary<string, Conta> dicionario = new Dictionary<string, Conta>();
// preenche o dicionrio
foreach(KeyValuePair<string, Conta> par in dicionario)
{
// podemos acessar a chave atual do dicionrio
string chave = par.Key;
// e podemos pegar o valor associado chave
Conta valor = par.Value;
}
Assim como no HashSet, quando iteramos em um dicionrio, seus elementos no esto em nenhuma or-
dem em particular, logo no podemos depender da ordem dos elementos do dicionrio. Quando estamos
trabalhando com um algoritmo que depende da ordem dos elementos, precisamos utilizar um outro tipo de
dicionrio chamado SortedDictionary. O uso do SortedDictionary igual ao do Dictionary, porm seus
elementos esto sempre na ordem crescente das chaves do dicionrio.
No C, temos uma interface implementada por todos os tipos os tipos de dicionrios, a IDictionary, alm
disso, os dicionrios tambm implementam a interface ICollection do C, porm eles so colees de
KeyValuePair. Podemos ver sua hierarquia na imagem a seguir:
A hierarquia das colees do C fca da seguinte forma:
Captulo - Lidando com conjuntos - Iterando no dicionrio - Pgina
Material do Treinamento C e Orientao a Objetos
. Exvncc:os
) Em nosso banco, precisamos implementar uma nova busca de contas por nome do titular. Para imple-
mentarmos essa busca, utilizaremos os dicionrios do C.
No formulrio principal da aplicao, coloque um novo campo de texto que receber qual o nome
do titular da busca. Chame esse campo de textoBuscaTitular. Alm desse novo campo de texto, co-
loque tambm um novo boto que quando clicado executar a busca por nome, chame esse boto de
botaoBusca. O seu formulrio deve fcar parecido com o que segue:
Para implementarmos essa busca por nome de titular, o formulrio precisa de um novo atributo do tipo
Dictionary. Quais devem ser os tipos da chave e do valor do dicionrio? Agora que temos o dicionrio,
Captulo - Lidando com conjuntos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
toda vez que criamos uma nova conta, precisamos adicion-la lista de contas, no combo box e no di-
cionrio de contas, mas como o formulrio possui um mtodo especializado em adicionar novas contas,
o AdicionaConta, s precisamos modifcar a implementao desse mtodo. Repare que como o cdigo
est encapsulado, precisamos apenas modifcar esse mtodo que tudo funcionar automaticamente.
public partial class Form1 : Form
{
private Dictionary<string, Conta> dicionario;
private void Form1_Load(object sender, EventArgs e)
{
this.dicionario = new Dictionary<string, Conta>();
// resto do mtodo
}
public void AdicionaConta(Conta conta)
{
contas.Add(conta);
comboContas.Items.Add(conta);
// agora s precisamos atualizar o dicionrio
this.dicionario.Add(conta.Titular.Nome, conta);
}
// Resto do cdigo da classe
}
Agora que j preparamos o dicionrio, precisamos apenas utiliz-lo para implementar a ao do boto de
busca por titular.
private void botaoBusca_Click(object sender, EventArgs e)
{
// Precisamos primeiro buscar qual o nome do titular que foi digitado
// no campo de texto
string nomeTitular = textoBuscaTitular.Text;
// Agora vamos usar o dicionrio para fazer a busca.
// Repare como o cdigo de busca fica simples
Conta conta = dicionario[nomeTitular];
// E agora s precisamos mostrar a conta que foi encontrada na busca
textoTitular.Text = conta.Titular.Nome;
textoNumero.Text = Convert.ToString(conta.Numero);
textoSaldo.Text = Convert.ToString(conta.Saldo);
}
Captulo - Lidando com conjuntos - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) (Opcional) No cdigo do exerccio passado, quando encontramos uma conta dentro do dicionrio, es-
tamos apenas atualizando as informaes que so mostradas nos campos textoNumero, textoSaldo e
textoTitular, porm quando tentamos fazer uma operao, sempre utilizamos o item que est seleci-
onado atualmente no comboContas. Precisamos utilizar a conta devolvida pelo dicionrio para atualizar
o valor selecionado do comboContas, para fazer isso, precisamos apenas atribuir a conta que queremos
selecionar na propriedade SelectedIndex do comboContas:
private void botaoBusca_Click(object sender, EventArgs e)
{
string nomeTitular = textoBuscaTitular.Text;
Conta conta = dicionario[nomeTitular];
// Agora vamos atualizar o item selecionado do comboContas:
comboContas.SelectedItem = conta;
}
Quando escrevemos na propriedade SelectedItem, o Windows Forms automaticamente chama a ao
de mudana de item selecionado do combo box (o comboContas_SelectedIndexChanged), logo no pre-
cisamos nos preocupar em atualizar os campos de texto no cdigo da busca por nome do titular.
) O que acontece quando tentamos buscar um nome de titular que no existe? Tente modifcar o cdigo do
formulrio para corrigir o problema.
Captulo - Lidando com conjuntos - Exerccios - Pgina
C
LINQ e Lambda
Nosso banco armazena uma lista de contas. Essas contas possuem os mais variados correntistas, saldos e
tipos. Muitas vezes, precisamos fltr-las de alguma forma. Por exemplo, se quisermos pegar todas as contas
com saldo maior que reais, fazemos:
var lista = new List<Conta>();
// inserimos algumas contas
lista.Add(...);
// cria lista que usaremos para guardar os elementos filtrados
var filtrados = new List<Conta>();
foreach(var c : lista)
{
if(c.Saldo > 2000)
{
filtrados.Add(c);
}
}
// agora a variavel "filtrados" tem as contas que queremos!
Se complicarmos ainda mais o fltro (por exemplo, contas com saldo maior que e menor que ,
com data de abertura entre os anos e , ...), nosso cdigo fcar tambm mais complexo, alm disso,
se quisssemos aplicar um fltro em uma lista com outro tipo de objeto, teramos que repetir novamente o
cdigo do foreach em diversos pontos da aplicao.
Material do Treinamento C e Orientao a Objetos
. F:t1nos c1:t:znNoo o LINQ
Para fltrar uma lista, seria muito mais interessante que a prpria coleo tivesse algummtodo que recebesse
a condio que queremos aplicar nesse fltro e j implementasse a lgica do foreach, algo como:
List<Conta> contas = // inicializa a lista
var filtradas = contas.Filtra(condio);
Mas como passar a condio para esse fltro? Teramos que enviar umbloco de cdigo que aceita ou rejeita os
valores da coleo. Para passar um bloco de cdigo que pode ser utilizado por um mtodo, o C introduziu
as funes annimas ou lambdas. As funes annimas funcionam como mtodos estticos da linguagem
com uma declarao simplifcada. Para declarar uma funo annima que recebe um argumento do tipo
Conta utilizamos o seguinte cdigo:
(Conta c) => { // implementao da funo annima }
Dentro do bloco de implementao da funo annima, colocaremos a implementao da condio:
(Conta c) => { return c.Saldo > 2000; }
E agora essa funo pode ser passada para dentro do mtodo Filtra:
contas.Filtra((Conta c) => { return c.Saldo > 2000; });
No C temos exatamente a implementao dessa ideia, mas o mtodo se chama Where ao invs de Filtra.
Ento, para buscarmos todas as contas que tmumsaldo maior do que , utilizaramos o seguinte cdigo:
List<Conta> contas = // inicializa a lista
var filtradas = contas.Where((Conta c) => { return c.Saldo > 2000; });
Agora que temos a lista de contas fltradas, podemos, por exemplo, iterar nessa lista:
foreach(Conta conta in filtradas)
{
MessageBox.Show(conta.Titular.Nome);
}
A biblioteca do C que defne o mtodo Where chamada LINQ, a Language Integrated Query.
Captulo - LINQ e Lambda - Filtros utilizando o LINQ - Pgina
Material do Treinamento C e Orientao a Objetos
. S:mvt:v:cnNoo n ovctnnnXo oo tnmnon
Veja que, no cdigo do lambda que passamos como argumento para o Where, defnimos que o argumento
da funo annima do tipo Conta porque a lista da varivel contas do tipo Conta. Repare que o tipo do
argumento do lambda na verdade redundante e por isso, desnecessrio:
var filtradas = contas.Where(c => { return c.Saldo > 2000; });
Alm disso, quando declaramos uma funo annima que tem apenas uma linha que devolve um valor,
podemos remover inclusive as chaves e o return da declarao do lambda:
var filtradas = contas.Where(c => c.Saldo > 2000 );
Veja que esse cdigo fnal muito mais simples do que a declarao inicial que utilizamos para a funo
annima.
. Oc1nos mv1ooos oo LINQ
Agora imagine que queremos saber qual a soma do saldo de todas as contas que esto cadastradas dentro
da aplicao. Para resolver esse problema, teramos que fazer um cdigo parecido com o seguinte:
List<Conta> contas = // inicializa a lista de contas
double total = 0.0;
foreach(Conta c in contas)
{
total += c.Saldo;
}
Porm esse tipo de cdigo tambm acaba fcando repetitivo. Quando queremos fazer a soma dos elementos
de uma lista, podemos utilizar o mtodo Sum do LINQ, passando um lambda que fala qual a propriedade
da conta que queremos somar:
double total = contas.Sum(c => c.Saldo);
Comessa linha de cdigo conseguimos o mesmo efeito do foreach anterior. Almdo Sum, tambmpodemos
utilizar o mtodo Average para calcular a mdia dos valores, Count para contar o nmero de valores que
obedecem algum critrio, Min para calcular o menor valor e Max para calcular o maior valor:
List<Conta> contas = // inicializa a lista
Captulo - LINQ e Lambda - Simplifcando a declarao do lambda - Pgina
Material do Treinamento C e Orientao a Objetos
// soma dos saldos de todas as contas
double saldoTotal = contas.Sum(c => c.Saldo);
// media do saldo das contas
double mediaDosSaldos = contas.Average(c => c.Saldo);
// nmero de contas que possuem Numero menor do que 1000
int numero = contas.Count(c => c.Numero < 1000);
int menorNumero = contas.Min(c => c.Numero);
double maiorSaldo = contas.Max(c => c.Saldo);
Quando utilizamos esses mtodos de agregao emuma lista comtipos primitivos, o lambda umargumento
opcional. Por exemplo, se tivssemos uma lista de double, poderamos utilizar o seguinte cdigopara calcular
a mdia dos nmeros:
List<double> saldos = // inicializa a lista
double media = saldos.Average();
. U1:t:znNoo o LINQcomoc1nos 1:vos
O LINQ, alm de trabalhar com listas, tambm pode ser utilizados com outros tipos de colees, podemos
utilizar o LINQcomqualquer objeto que implemente a interface IEnumerable, ou seja, ele pode ser utilizado
com qualquer objeto que possa ser passado para a instruo foreach. Isso inclui todos os tipos de colees
(Listas, conjuntos e dicionrios) e arrays.
. MvtnonnNoo ns ncscns c1:t:znNoo n s:N1nxv ov qcvn:vs
Vimos que utilizando o LINQ podemos fazer fltros e agregaes de uma forma fcil em qualquer coleo
do C, porm quando precisamos fazer um fltro complexo, o lambda pode fcar com um cdigo complexo.
E por isso, a Microsof decidiu facilitar ainda mais o uso do LINQ.
Para implementarmos um fltro, em vez de utilizarmos o mtodo Where, podemos utilizar uma sintaxe que
foi baseada na linguagem de busca em banco de dados, a SQL. Para comearmos um fltro utilizando essa
nova sintaxe, precisamos comear o fltro com a palavra from criando uma varivel que ser utilizada para
navegar na lista:
var filtradas = from c in contas
Captulo - LINQ e Lambda - Utilizando o LINQ com outros tipos - Pgina
Material do Treinamento C e Orientao a Objetos
Agora para colocarmos uma condio nesse fltro, utilizamos a palavra where passando qual a condio a
que a conta deve obedecer para aparecer como resultado desse fltro:
var filtradas = from c in contas
where c.Numero < 2000
E por fm, precisamos apenas informar o que ser selecionado utilizando o select:
var filtradas = from c in contas
where c.Numero < 2000
select c;
Com esse cdigo, estamos defnindo um fltro que devolver apenas as contas que tm nmero menor do
que .
Quando o compilador da linguagem C encontra o fltro que defnimos, esse cdigo convertido para uma
chamada para o mtodo Where que vimos anteriormente. Essa nova sintaxe apenas um jeito de esconder a
complexidade do lambda.
. Pnnn snnvn mn:s vno)vovs v on)v1os nNN:mos
Muitas vezes, quando estamos usando o LINQ, o fltro no precisa retornar todas as informaes dos objetos
da lista que est sendo processada. Podemos estar interessados em buscar apenas o nmero das contas que
obedecem os critrios da busca, para isso precisamos apenas mudar o select do LINQ.
List<Conta> contas = // inicializa a lista
var resultado = from c in contas where <condio da busca> select c.Numero;
O resultado dessa busca ser uma coleo de nmeros inteiros.
Mas e quando queremos devolver mais atributos da conta? Como no LINQ podemos apenas devolver um
objeto como resultado da query, teramos que criar uma classe que contm os atributos que sero devolvidos
pela query, mas muitas vezes ns fazemos a busca e utilizamos o resultado dentro de um nico ponto da
aplicao (dentro de um mtodo, por exemplo). Nesses casos, podemos deixar o compilador do C cuidar
da criao desse objeto annimo:
var resultado = from c in contas
where <condio da busca>
select new { c.Numero, c.Titular };
Captulo - LINQ e Lambda - Para saber mais projees e objetos annimos - Pgina
Material do Treinamento C e Orientao a Objetos
Nesse cdigo, o compilador do C cria um novo tipo que ser utilizado para guardar o resultado da busca.
Esse tipo no possui um nome dentro do cdigo e por isso o objeto devolvido chamado de Objeto An-
nimo. Quando utilizamos o objeto annimo no LINQ, somos forados a utilizar a inferncia de tipos (palavra
var).
No exemplo, o objeto annimo devolvido pelo compilador possui as propriedades Titular e Numero, por-
tanto podemos utiliz-las dentro de um foreach:
foreach (var c in filtradas)
{
// aqui dentro podemos apenas usar o Titular e o Numero,
// se tentarmos acessar o Saldo teremos um erro de compilao
MessageBox.Show(c.Titular.Nome + " " + c.Numero);
}
. Exvncc:os
) Crie umnovo formulrio chamado FormRelatorios. Utiliz-lo-emos para mostrar o resultado de queries
feitas utilizando o LINQ.
No editor grfco desse novo formulrio, abra a janela Toolbox e adicione o componente ListBox, chame-
o de listaResultado. Utilizaremos esse ListBox para mostrar os resultados devolvidos pelo LINQ.
Agora vamos criar nosso primeiro relatrio, o de busca de contas com saldo maior do que , atravs
de um novo boto dentro da janela. Utilize o nome botaoFiltroSaldo:
Quando esse boto for clicado, queremos executar um fltro com o LINQ:
private void botaoFiltroSaldo_Click(object sender, EventArgs e)
{
// Aqui implementaremos o filtro
}
Como os relatrios precisaro da lista de contas, pediremos essa lista no construtor da janela:
Captulo - LINQ e Lambda - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
public partial class FormRelatorios : Form
{
private List<Conta> contas;
public FormRelatorios(List<Conta> contas)
{
InitializeComponent();
this.contas = contas;
}
// outros mtodos da janela.
}
Dentro da ao do boto, implemente a busca por todas as contas que possuem saldo maior do que .
Agora utilizaremos o ListBox para mostrar as contas devolvidas pelo LINQ.
O ListBox funciona como o ComboBox. Quando queremos adicionar uma nova linha, precisamos adicio-
nar o objeto que queremos mostrar dentro da propriedade Items do ListBox. Ele mostrar o ToString()
do objeto adicionado. Como utilizaremos esse ListBox para mostrarmos o resultado de diversas buscas,
precisamos limpar o resultado anterior antes de mostrar o prximo, e fazemos isso atravs do mtodo
Clear() da propriedade Items:
private void botaoFiltroSaldo_Click(object sender, EventArgs e)
{
listaResultado.Items.Clear();
var resultado = // query do LINQ
foreach (var c in resultado)
{
listaResultado.Items.Add(c);
}
}
Agora para testarmos essa busca, vamos adicionar um novo boto dentro do formulrio principal, classe
Form1, chamado botaoRelatorio que instanciar o formulrio FormRelatorios passando a lista de contas
como argumento e depois chamar o ShowDialog para mostrar essa nova janela:
private void botaoRelatorio_Click(object sender, EventArgs e)
{
FormRelatorios form = new FormRelatorios(this.contas);
form.ShowDialog();
}
) Agora vamos implementar um novo relatrio com o LINQ. Dessa vez, queremos listar todas as contas
antigas (numero menor do que ) com saldo maior do que . Para isso crie um novo boto na janela
de relatrios que quando clicado executar a query do LINQna lista de contas e mostra o resultado dentro
do ListBox que criamos no exerccio anterior.
) Agora vamos colocar resumos das informaes contidas no relatrio. Para isso, colocar dentro do relatrio
um novo GroupBox que ter o ttulo Resumo. Dentro desse GroupBox, mostraremos, por exemplo, qual o
Captulo - LINQ e Lambda - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
saldo da conta de maior Saldo e qual o Saldo total de todas as contas.
Almdesse GroupBox, coloque algumas labels para mostrar os resumos desse relatrio. Oprimeiro deve
mostrar o texto Saldo Total, o segundo, o texto Maior Saldo. Os dois labels restantes sero utilizados
para mostrar os resumos chame o terceiro label de labelSaldoTotal e o ltimo de labelMaiorSaldo.
Seu formulrio deve fcar parecido com a fgura a seguir:
Depois de modifcarmos o formulrio, vamos modifcar as aes do boto para que elas, alm de fazerem
a busca, tambm atualizem o resumo com as informaes da busca. Podemos extrair os resumos da
seguinte forma:
private void botaoFiltroSaldo_Click(object sender, EventArgs e)
{
listaResultado.Items.Clear();
var resultado = // query do LINQ
foreach (var c in resultado)
{
listaResultado.Items.Add(c);
}
double saldoTotal = resultado.Sum(conta => conta.Saldo);
double maiorSaldo = resultado.Max(conta => conta.Saldo);
labelSaldoTotal.Text = Convert.ToString(saldoTotal);
labelMaiorSaldo.Text = Convert.ToString(maiorSaldo);
}
Experimente a API do LINQ, tentando criar novas queries e extrair outras informaes para o resumo do
relatrio.
Captulo - LINQ e Lambda - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
. OnovNnNoo cotvovs comLINQ
Almde fazermos buscas e projees, podemos tambmutilizar o LINQpara ordenar colees de elementos.
Para isso precisamos apenas colocar um orderby dentro da query. Por exemplo, para buscarmos todas as
contas com saldo maior do que ordenadas pelo nome do titular, utilizamos o seguinte cdigo:
List<Conta> contas = // inicializa a lista de contas
var resultado = from c in contas
where c.Saldo > 10000
orderby c.Titular.Nome
select c;
Com isso temos uma lista de contas ordenadas pelo nome do titular de forma ascendente (alfabtica). Assim
como podemos fazer a ordenao ascendente, tambm podemos fazer a ordenao descendente utilizando
a palavra descending:
List<Conta> contas = // inicializa a lista de contas
var resultado = from c in contas
where c.Saldo > 10000
orderby c.Titular.Nome descending
select c;
Mas e se tivermos dois titulares com exatamente o mesmo nome? Nesse caso, podemos defnir um segundo
critrio para desempatar a ordenao. Cada um dos critrios da ordenao fca separado por vrgula no
orderby. No exemplo, para desempatarmos a ordenao utilizando o nmero da conta, utilizamos o seguinte
cdigo:
List<Conta> contas = // inicializa a lista de contas
var resultado = from c in contas
where c.Saldo > 10000
orderby c.Titular.Nome descending, c.Numero
select c;
O segundo critrio de ordenao tambm pode ter opcionalmente a palavra descending:
List<Conta> contas = // inicializa a lista de contas
var resultado = from c in contas
where c.Saldo > 10000
orderby c.Titular.Nome descending, c.Numero descending
select c;
Assim como no caso do fltro, as ordenaes do LINQ tambm so traduzidas para chamadas de mtodo
pelo compilador do C. Quando colocamos um orderby na busca, o compilador chama o mtodo OrderBy
(ou OrderByDescending no caso de uma ordenao descendente). A query com o fltro e a ordenao pelo
titular fca da seguinte forma:
Captulo - LINQ e Lambda - Ordenando colees com LINQ - Pgina
Material do Treinamento C e Orientao a Objetos
var resultado = contas
.Where(c => c.Saldo > 10000)
.OrderBy(c => c.Titular.Nome);
Quando colocamos uma ordenao secundria, o compilador do C chama o mtodo ThenBy (ou
ThenByDescending no caso de uma ordenao secundria descendente):
var resultado = contas
.Where(c => c.Saldo > 10000)
.OrderBy(c => c.Titular.Nome)
.ThenBy(c => c.Numero);
. Exvncc:os - OnovNnXo
) Vamos adicionar uma ordenao na tela de relatrios. Faa com que os botes que geram os relatrios
mostrem as contas ordenadas pela ordem alfabtica do nome do titular.
) (Opcional) Agora tente fazer a mesma ordenao do exerccio passado utilizando o mtodo OrderBy do
LINQ.
) (Opcional) Tente utilizar tambm uma ordenao secundria pelo nmero da conta em seus relatrios.
Captulo - LINQ e Lambda - Exerccios - Ordenao - Pgina
C
System.IO
Agora que j vimos que podemos utilizar o C para desenvolver um sistema orientado a objetos, vamos
aprender como utilizar as bibliotecas do System.IO para ler e escrever dados em arquivos.
. Lv:1cnn ov nnqc:vos
A entrada de dados no C funciona em duas etapas. Na primeira etapa, temos uma classe abstrata que re-
presenta uma sequncia de bytes na qual podemos realizar operaes de leitura e escrita. Essa classe abstrata
chamada de Stream.
Como o Stream uma classe abstrata, no podemos us-la diretamente, precisamos de uma implementa-
o para essa classe. No caso de leitura ou escrita em arquivos, utilizamos um tipo de Stream chamado
FileStream, que pode ser obtido atravs do mtodo esttico Open da classe File. Quando utilizamos o Open,
devemos passar o nome do arquivo que ser aberto e devemos inform-lo o que queremos fazer com o ar-
quivo (ler ou escrever).
Para abrirmos o arquivo entrada.txt para leitura, utilizamos o cdigo a seguir:
Stream entrada = File.Open("entrada.txt", FileMode.Open);
Agora que temos o Stream, podemos ler seu prximo byte utilizando o mtodo ReadByte.
byte b = entrada.ReadByte();
Porm, trabalhar com bytes no fcil, queremos trabalhar com textos! Portanto vamos utilizar a segunda
parte da leitura.
Material do Treinamento C e Orientao a Objetos
Para facilitar a leitura de Streams, o C nos oferece uma classe chamada StreamReader, responsvel por ler
caracteres ou strings de um Stream. O StreamReader precisa saber qual a Stream que ser lida, portanto
passaremos essa informao atravs de seu construtor:
StreamReader leitor = new StreamReader(entrada);
Para ler uma linha do arquivo, utilizamos o mtodo ReadLine do StreamReader:
string linha = leitor.ReadLine();
Enquanto o arquivo no terminar, o mtodo ReadLine() devolve um valor diferente de nulo, portanto, po-
demos ler todas as linhas de um arquivo com o seguinte cdigo:
string linha = leitor.ReadLine();
while(linha != null)
{
MessageBox.Show(linha);
linha = leitor.ReadLine();
}
Assim que terminamos de trabalhar com o arquivo, devemos sempre lembrar de fechar o Stream e o
StreamReader:
leitor.Close();
entrada.Close();
O cdigo completo para ler de um arquivo fca da seguinte forma:
Stream entrada = File.Open("entrada.txt", FileMode.Open);
StreamReader leitor = new StreamReader(entrada);
string linha = leitor.ReadLine();
while(linha != null)
{
MessageBox.Show(linha);
linha = leitor.ReadLine();
}
leitor.Close();
entrada.Close();
Porm, o arquivo pode no existir e, nesse caso, o C lana a FileNotFoundException. Devemos, portanto,
verifcar se o arquivo existe antes de abri-lo para leitura. Podemos verifcar se um arquivo existe utilizando
o mtodo Exists da classe File:
Captulo - System.IO - Leitura de arquivos - Pgina
Material do Treinamento C e Orientao a Objetos
if(File.Exists("entrada.txt"))
{
// Aqui temos certeza que o arquivo existe
}
O cdigo da leitura com a verifcao fca assim:
if(File.Exists("entrada.txt"))
{
Stream entrada = File.Open("entrada.txt", FileMode.Open);
StreamReader leitor = new StreamReader(entrada);
string linha = leitor.ReadLine();
while(linha != null)
{
MessageBox.Show(linha);
linha = leitor.ReadLine();
}
leitor.Close();
entrada.Close();
}
LvNoo 1ooo o coN1voo ov cmnnqc:vo
Vimos que para ler todas as linhas de um arquivo, precisamos utilizar o mtodo ReadLine at
que o retorno seja o valor null, mas isso trabalhoso.
Ao invs de chamar o mtodo ReadLine para cada linha, podemos utilizar o mtodo ReadToEnd
da classe StreamReader. Esse mtodo devolve uma string com todo o contedo do arquivo.
. EscnvvvNoo vmnnqc:vos
Assimcomo a leitura, a escrita tambmacontece emduas etapas. Na primeira etapa, trabalhamos novamente
escrevendo bytes para a sada. Para isso utilizaremos novamente a classe abstrata Stream.
Para escrevermos emumarquivo, precisamos primeiro abri-lo emmodo de escrita utilizando o mtodo Open
do File passando o modo FileMode.Create:
Stream saida = File.Open("saida.txt", FileMode.Create);
Porm, no queremos trabalhar com Bytes, ento utilizaremos uma classe especializada em escrever em um
Stream chamada StreamWriter.
StreamWriter escritor = new StreamWriter(saida);
Captulo - System.IO - Escrevendo em arquivos - Pgina
Material do Treinamento C e Orientao a Objetos
Podemos escrever uma linha com o StreamWriter utilizando o mtodo WriteLine:
escritor.WriteLine("minha mensagem");
Depois que terminamos de utilizar o arquivo, precisamos fechar todos os recursos:
escritor.Close();
saida.Close();
O cdigo completo para escrever no arquivo fca da seguinte forma:
Stream saida = File.Open("saida.txt", FileMode.Create);
StreamWriter escritor = new StreamWriter(saida);
escritor.WriteLine("minha mensagem");
escritor.Close();
saida.Close();
Repare que, por usarmos uma classe abstrata, podemos ento trocar facilmente a classe concreta por outra.
Por exemplo, poderamos ler de um Socket, ou de uma porta serial, e o cdigo seria o mesmo: basta a classe
ser flha de Stream. Repare que o uso de classes abstratas e polimorfsmo nos possibilita ler/escrever em
diferentes lugares com o mesmo cdigo. Veja que a prpria Microsof fez bom uso de orientao a objetos
para facilitar a vida dos desenvolvedores.
O IO do C pode ser esquematizado pela seguinte fgura:
ONov os nnqc:vos sXo cnnvnoos
Quando passamos apenas o nome do arquivo no cdigo do File.Open, o C procura esse arquivo
dentro da pasta em que a aplicao executada. No caso de executarmos a aplicao pelo Visual
Studio, a pasta utilizada pela aplicao ser a pasta em que o projeto foi criado.
Captulo - System.IO - Escrevendo em arquivos - Pgina
Material do Treinamento C e Orientao a Objetos
. GvnvNc:nNoo os nnqc:vos como cs:Nc
Toda vez que abrimos um arquivo dentro de um programa C, precisamos fech-lo utilizando o mtodo
Close. Devemos garantir que o Close ser executado mesmo quando o cdigo lana uma exceo durante
sua execuo, para isso podemos utilizar o bloco finally:
Stream arquivo = null;
StreamReader leitor = null;
try
{
arquivo = File.Open("arquivo.txt", FileMode.Open);
leitor = new StreamReader(arquivo);
// utiliza o arquivo
}
catch (Exception ex)
{
// Executa o tratamento do erro que aconteceu
}
finally
{
// fecha o arquivo e o leitor
// antes de fecharmos, precisamos verificar que o arquivo e o leitor foram
// realmente criados com sucesso
if(leitor != null)
{
leitor.Close();
}
if(arquivo != null)
{
arquivo.Close();
}
}
Veja que o cdigo para lidar corretamente comos arquivos pode fcar muito complicado. Ao invs de cuidar-
mos manualmente dos arquivos, podemos pedir para a linguagem C cuidar do gerenciamento utilizando o
bloco using.
Dentro de umbloco using podemos instanciar umrecurso que queremos que seja gerenciado pelo C, como
por exemplo um arquivo:
using (Stream arquivo = File.Open("arquivo.txt", FileMode.Open))
{
// o arquivo s fica aberto dentro desse bloco.
Captulo - System.IO - Gerenciando os arquivos com o using - Pgina
Material do Treinamento C e Orientao a Objetos
}
// se tentarmos utilizar o arquivo fora do bloco using teremos um erro de compilao.
Tambm podemos utilizar o using para gerenciar o StreamReader:
using(Stream arquivo = File.Open("arquivo.txt", FileMode.Open))
using(StreamReader leitor = new StreamReader(arquivo))
{
// aqui dentro voc pode utilizar tanto o leitor quanto o arquivo
}
Ousing automaticamente fecha os arquivos utilizados dentro do bloco mesmo quando uma exceo lanada
pelo cdigo.
Podemos utilizar o bloco using para gerenciar qualquer classe que implemente a interface IDisposable do
C.
. Exvncc:os
) Vamos agora criar umpequeno editor de texto para trabalharmos comarquivos. Dentro do Visual C, crie
um novo projeto do tipo Windows Form Application chamado EditorDeTexto. Dentro desse projeto,
adicione um TextBox que ser o campo de texto onde o usurio digitar o texto que deve ser gravado
no arquivo, chame-o de textoConteudo. Alm desse campo de texto, adicione tambm um boto que
quando clicado gravar o campo de texto em um arquivo, chame-o de botaoGrava.
Para permitir que o usurio possa digitar diversas linhas no campo de texto, clique como boto direito no
TextBox e selecione a opo Properties. Dentro da janela Properties, encontre a propriedade chamada
Multiline e mude seu valor para true. Agora estique o TextBox para que o seu formulrio fque parecido
com o da imagem:
Captulo - System.IO - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
Agora que temos o formulrio pronto, faa com que o carregamento do programa preencha o campo de
texto do formulrio com o contedo de um arquivo chamado texto.txt. No se esquea de verifcar que
o arquivo existe antes de abri-lo
private void Form1_Load(object sender, EventArgs e)
{
if(File.Exists("texto.txt"))
{
Stream entrada = File.Open("texto.txt", FileMode.Open);
StreamReader leitor = new StreamReader(entrada);
string linha = leitor.ReadLine();
while(linha != null)
{
textoConteudo.Text += linha;
linha = leitor.ReadLine();
}
leitor.Close();
entrada.Close();
}
}
) Implemente a ao do boto Gravar. Quando clicado, esse boto deve gravar o contedo do TextBox
dentro de um arquivo chamado texto.txt:
private void botaoGrava_Click(object sender, EventArgs e)
{
Stream saida = File.Open("texto.txt", FileMode.Create);
StreamWriter escritor = new StreamWriter(saida);
escritor.Write(textoConteudo.Text);
escritor.Close();
Captulo - System.IO - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
saida.Close();
}
) Existe um mtodo dentro da classe StreamReader chamado ReadToEnd que l todas as linhas do arquivo.
Modifque o editor para utilizar esse mtodo.
) Modifque o cdigo do editor de texto para que ele utilize o using para fechar os arquivos.
) (Opcional) Quando queremos um programa que trabalha com o terminal do sistema operacional, preci-
samos criar um tipo diferente de projeto no Visual Studio, o Console Application.
Para criarmos a aplicao que usa o terminal, devemos seguir os mesmos passos da criao do Windows
Form Application, porm escolheremos o Console Application na janela do assistente.
Quando criamos uma aplicao no console, o Visual Studio cria um novo projeto com uma classe que
contm um mtodo chamado Main. esse mtodo que ser executado quando apertarmos F5 para rodar
o programa.
Dentro do Main, podemos imprimir uma mensagem no terminal utilizando o Console.WriteLine pas-
sando a mensagem:
Console.WriteLine("Mensagem que vai para o terminal");
Quando queremos ler uma linha que o usurio digitou no terminal, utilizamos um atributo do tipo
TextReader da classe Console chamado In:
TextReader leitor = Console.In;
No TextReader, temos o mtodo ReadLine que consegue ler uma linha do terminal.
string linha = leitor.ReadLine();
O ReadLine devolve uma string no nula, enquanto o usurio continuar enviando novas linhas.
while(linha != null) {
// usa o texto da linha atual
linha = leitor.ReadLine();
}
Quando o usurio manda a combinao Ctrl+z para a aplicao, o leitor devolve null.
Crie um programa que l e imprime as linhas que o usurio digita no terminal at que seja enviada a
combinao Ctrl+z.
) (Opcional) Quando fzemos a leitura de um arquivo, utilizamos o cdigo:
using(Stream entrada = File.Open("entrada.txt", FileMode.Open))
using(StreamReader leitor = new StreamReader(entrada))
{
// usa o leitor
}
Captulo - System.IO - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
No C, o StreamReader uma subclasse da classe abstrata TextReader, a mesma que utilizamos para ler
dados do terminal, logo podemos reescrever o cdigo da leitura de arquivo para:
using(Stream entrada = File.Open("entrada.txt", FileMode.Open))
using(TextReader leitor = new StreamReader(entrada))
{
// usa o leitor
}
Quais modifcaes deveramos fazer nesse cdigo para ler o texto que o usurio digitou no terminal?
. Pnnn snnvn mn:s oNov cotocnn os nnqc:vos on nvt:cn-
Xo
Precisamos tomar muito cuidado ao escrever programas que guardam informaes dentro de arquivos.
Como dito anteriormente, quando utilizamos o File.Open, o C procura o arquivo na pasta em que a apli-
cao est sendo executada, porm muitas vezes os programas escritos so instalados em pastas do sistema
operacional, por exemplo C:/Arquivos de Programas, nesse caso o programa tentar escrever as informa-
es dentro de um pasta do sistema operacional e por isso, ele s pode ser executado por um administrador
do sistema.
Normalmente, quando escrevemos uma aplicao com algum erro de programao, isso no afeta o sistema
operacional pois o programa no executado com permisses de administrador e, portanto, no pode fazer
modifcaes perigosas no sistema. Ento, para que a aplicao no precise ser executado como administra-
dor, podemos fazer com que ela escreva, por exemplo, na pasta de documentos do usurio logado.
Quando queremos recuperar o caminho para uma pasta especial do sistema operacional, podemos utilizar
uma classe do C chamada Environment do namespace System. Nessa classe, podemos invocar o mtodo
GetFolderPath para recuperar o caminho para uma pasta do sistema. O mtodo GetFolderPath recebe
como argumento uma constante que indica qual a pasta que queremos. Para recuperarmos o caminho
para a pasta de documentos do usurio logado, podemos utilizar o seguinte cdigo:
string pastaDocumentos = Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments);
Os outros valores aceitos pelo mtodo GetFolderPath podem ser encontrados nessa pgina: http://msdn.
microsof.com/en-us/library/system.environment.specialfolder.aspx
Agora se quisermos abrir um arquivo chamado entrada.txt dentro da pasta de documentos, precisamos
combinar o caminho da pasta com o nome do arquivo. Para resolver esse problema, utilizamos o mtodo
Combine da classe Path do namespace System.IO:
string pastaDocumentos = Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments);
Captulo - System.IO - Para saber mais onde colocar os arquivos da aplicao - Pgina
Material do Treinamento C e Orientao a Objetos
string caminhoArquivo = Path.Combine(pastaDocumentos, "entrada.txt");
Captulo - System.IO - Para saber mais onde colocar os arquivos da aplicao - Pgina
C
Manipulao de strings
Em C textos so representados por objetos do tipo string. Para criar um texto, podemos usar a seguinte
sintaxe:
string titulo= "Arquitetura e Design de Software";
MessageBox.Show(titulo); // imprime o contedo
Podemos ainda juntar duas strings:
string titulo = "Arquitetura" + " e " + " Design de Software";
titulo += " ! " // concatena a ! no fim do texto
Usando a concatenao, podemos inserir o valor de qualquer varivel no meio de nosso texto:
int idade = 42;
MessageBox.Show("a idade atual " + idade);
Mas fcar concatenando strings nem sempre fcil, principalmente se temos muitos valores. Podemos usar
uma alternativa, fazendo o prprio C fazer essa concatenao por ns. Para isso, basta indicar na string a
posio que quer inserir a varivel usando a sintaxe {posicao}, e passar o valor correspondente em ordem:
string nome = "Guilherme";
int idade = 42;
Console.WriteLine("Ol {0}, a sua idade {1}", nome, idade);
Caso precisemos armazenar a string j concatenada em uma varivel ao invs de a imprimir, basta usar o
mtodo Format:
Material do Treinamento C e Orientao a Objetos
string nome = "Guilherme"
int idade = 42;
string txt = string.Format("Ol {0}, a sua idade {1}", nome, idade);
MessageBox.Show(txt);
Imagine que temos uma linha de texto que separa os dados de um usurio do sistema atravs de vrgulas:
string texto = "guilherme silveira,42,so paulo,brasil";
Como separar cada uma das partes atravs da ,? A classe String conta tambm com um mtodo Split, que
divide a String em um array de Strings, dado determinado caractere como critrio:
string texto = "guilherme silveira,42,so paulo,brasil";
string[] colunas = texto.Split(',');
Sempre que chamamos ummtodo emumobjeto String, umnovo objeto criado e retornado pelo mtodo,
mas o original nunca modifcado. Strings so imutveis. Portanto ao tentarmos transformar em letra
maiscula o resultado pode no ser o esperado:
string curso = "fn13";
curso.ToUpper();
MessageBox.Show (curso); // imprime fn13
Sendo assim, quando queremos transformar em maisculo devemos atribuir o resultado do mtodo:
string curso = "fn13";
string maiusculo = curso.ToUpper();
MessageBox.Show (maiusculo); // imprime FN13
Podemos substituir parte do contedo de uma String, usando o mtodo Replace:
string curso = "fn13";
curso = curso.ToUpper();
curso = curso.Replace("1", "2");
MessageBox.Show (curso) // imprime FN23;
Podemos concatenar as invocaes de mtodo, j que uma string devolvida a cada invocao:
string curso = "fn13";
curso = curso.toUpper().Replace("1", "2");
MessageBox.Show (curso) // imprime FN23;
Captulo - Manipulao de strings - - Pgina
Material do Treinamento C e Orientao a Objetos
s vezes precisamos quebrar nossos textos em partes menores com base na quantidade de caracteres, ou
ainda, encontrar a posio de um caractere especfco dentro de nossa string:
string nomeCompleto = "guilherme silveira";
string nome = nomeCompleto.Substring(0,9);
MessageBox.Show (nome) // imprime guilherme;
E para buscar o caractere espao dentro de uma string:
int posicaoDoEspaco = nomeCompleto.IndexOf(" ");
MessageBox.Show (posicaoDoEspaco); // imprime 8
Ou ainda, usar esses mtodos emconjunto, para umexemplo mais avanado, no qual imprimimos o segundo
nome:
string nomeCompleto = "guilherme silveira";
int inicioDoSegundoNome = texto.IndexOf("s");
MessageBox.Show(nomeCompleto.Substring(inicioDoSegundoNome)); // imprime guilherme
. Exvncc:os
) Observe o seguinte trecho de cdigo:
string conteudo = "16,23,34,24,15,25,35,35,54,32";
string[] idades = ????;
foreach( var n in idades)
{
MessageBox.Show(n);
}
Qual trecho de cdigo deve substituir as ??? para imprimir todos os nmeros?
conteudo.Split(',');
conteudo.Replace(" ", " \n");
conteudo.Split(,);
conteudo.Split(' ');
Captulo - Manipulao de strings - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) Vamos agora melhorar o editor de texto que criamos no captulo anterior utilizando as operaes em
string! Inicialmente, vamos incluir a funcionalidade de busca de strings na aplicao.
Vamos criar mais um campo de texto no formulrio que ser utilizado pelo usurio para digitar o termo
que ser buscado no editor. Chame esse campo de texto de textoBusca. Alm do campo de texto, inclua
tambm um boto que, quando clicado, buscar o texto do textoBusca dentro do editor. Chame-o de
botaoBusca. Seu formulrio deve fcar parecido com o que segue:
Agora que atualizamos o formulrio, vamos implementar a funcionalidade de busca. Na ao do boto
de busca, vamos utilizar o mtodo IndexOf para implementar a busca:
private void botaoBusca_Click(object sender, EventArgs e)
{
string busca = textoBusca.Text;
string textoDoEditor = textoConteudo.Text;
int resultado = textoDoEditor.IndexOf(busca);
if(resultado >= 0)
{
MessageBox.Show("achei o texto " + busca);
}
else
{
MessageBox.Show("no achei");
}
}
Teste essa nova funcionalidade do programa.
) Agora vamos implementar a funcionalidade fnd/replace que muito comumnos editores de texto atuais.
Para isso, vamos adicionar mais um campo de texto no formulrio que ser o textoReplace, alm de um
novo boto que quando clicado trocar todas as ocorrncias de textoBusca por textoReplace dentro do
editor. Esse boto ser o botaoReplace.
Captulo - Manipulao de strings - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
) Vamos agora adicionar um novo boto no formulrio que quando clicado far com que o texto do editor
fque com letras maisculas. Utilize o mtodo ToUpper() da String para fazer esse trabalho.
) (Opcional) Adicione tambm um boto que utiliza o ToLower() da string.
) (Opcional) Agora vamos fazer com que o boto ToUpper altere apenas o pedao que o usurio selecionar
do texto digitado ao invs de todo o texto. Para isso, utilizaremos duas novas propriedades do TextBox
que lidam com seleo de texto: SelectionStart e SelectionLength.
A propriedade SelectionStart nos diz em qual posio, comeando em , do texto o usurio iniciou a
seleo. SelectionLength nos devolve quantos caracteres do texto esto selecionados atualmente.
Por exemplo, no texto abaixo:
Curso de C# da Caelum
Se o usurio selecionar a palavra Curso, SelectionStart devolver e SelectionLength, .
Agora vamos utilizar essas duas novas propriedades para implementar o ToUpper na seleo:
private void botaoToUpper_Click(object sender, EventArgs e)
{
int inicioSelecao = textoConteudo.SelectionStart;
int tamanhoSelecao = textoConteudo.SelectionLength;
// agora vamos utilizar o Substring para pegar o texto selecionado
string textoSelecionado = textoConteudo.Text
.Substring(inicioSelecao, tamanhoSelecao);
// alm do texto selecionado, precisamos do texto antes da seleo:
string antes = textoConteudo.Text
.Substring(0, inicioSelecao);
// e tambm do texto depois
string depois = textoConteudo.Text
.Substring(inicioSelecao + tamanhoSelecao);
// E agora s precisamos redefinir o campo texto
textoConteudo.Text = antes + textoSelecionado.ToUpper() + depois;
}
Tente fazer o mesmo para o boto ToLower.
Captulo - Manipulao de strings - Exerccios - Pgina
C
Apndice estendendo comportamentos atravs
de mtodos extras
Muitas vezes usamos classes criadas por outros desenvolvedores, como por exemplo todas as classes do .NET
framework. A classe string um bom exemplo e cheia de mtodos teis mas quem desenhou a classe no
colocou um mtodo para transformar uma palavra em seu plural, por exemplo. O que fazer se queremos o
plural de conta e banco gerado automaticamente?
Uma abordagem a criao de um mtodo esttico que pode ser chamado:
public static class StringUtil
{
public static string Pluralize(string texto)
{
if(texto.EndsWith("s"))
{
return texto;
}
else
{
return texto + "s";
}
}
}
Claro que esse mtodo uma abordagem bem simples para um algoritmo que capaz de retornar plurais,
mas j resolve o problema no caso geral. Agora podemos em todo lugar do nosso cdigo fazer:
string bancos = StringUtil.Pluralize("banco");
string contas = StringUtil.Pluralize("conta");
Material do Treinamento C e Orientao a Objetos
Por mais que a implementao funcione, o cdigo fca muito feio porque toda vez precisamos invocar o
mtodo esttico. No seria possvel estender a classe string para fazer algo como o cdigo a seguir?
String texto = "banco";
String plural = texto.Pluralize();
O C permite a criao de mtodos de extenso para classes que j existem atravs do uso da palavra using,
mas para isso devemos colocar nossa classe esttica dentro de um namespace e adicionar a palavra this ao
primeiro parmetro:
namespace MinhasExtensoes {
public static class StringExtensions
{
public static string Pluralize(this string texto)
{
if(texto.EndsWith("s"))
{
return texto;
}
else
{
return texto + "s";
}
}
}
}
Agora podemos:
using MinhasExtensoes;
string texto = "banco";
string plural = texto.Pluralize();
Note como, ao importar as extenses, todos os mtodos estticos de classes estticas pblicas dentro do
namespace importado estaro disponveis para serem acessados como se pertencessem a classe, apesar de
no pertencerem.
importante lembrar que o mtodo s pode ser acessado caso ainda no exista um outro mtodo com o
mesmo nome e tipos de parmetros na classe. Isto , no seria possvel estender a classe string com um
novo mtodo ToString() pois ele j existe. S podemos adicionar novos comportamentos.
Exatamente por isso pode ser perigoso adicionar mtodos como extenses sem cuidado nenhum: no futuro
algum pode adicionar esse mtodo classe que estendemos e agora nosso cdigo quebra pois no mais
compatvel. Somente estenda os comportamentos de uma classe caso seja necessrio.
Captulo - Apndice estendendo comportamentos atravs de mtodos extras - - Pgina
Material do Treinamento C e Orientao a Objetos
. Exvncc:os
) Queremos adicionar a todas as nossas contas a capacidade de uma Conta se transformar em XML. Para
isso o C j dispe uma API:
using System.IO;
using System.Xml.Serialization;
public static class Serializer {
public static string AsXml(Conta resource)
{
var stringWriter = new StringWriter();
new XmlSerializer(resource.GetType()).Serialize(stringWriter, resource);
return stringWriter.ToString();
}
}
Para acessar esse processo fazemos:
Conta conta = new Conta();
System.Console.Write(Serializer.AsXml(conta));
Como desejamos usar o recurso de extenso externa do C para poder adicionar um mtodo a todos
as contas do sistema, o que devemos colocar na linha comentada para defnir nosso mtodo?
using System.IO;
using System.Xml.Serialization;
namespace Caelum {
public static class ObjectExtensions
{
// Definio do mtodo
{
var stringWriter = new StringWriter();
new XmlSerializer(resource.GetType()).Serialize(stringWriter, resource);
return stringWriter.ToString();
}
}
}
// Uso
using System;
using Caelum;
Conta conta = new Conta();
Console.Write(conta.AsXml());
public static string AsXml(this Conta resource)
Captulo - Apndice estendendo comportamentos atravs de mtodos extras - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
public string AsXml(Conta resource)
public string AsXml(this Conta resource)
public static string AsXml(Conta resource)
public static extension string AsXml(Conta resource)
public static string AsXml(extension Conta resource)
) Em vez de adicionar o extension method a todas as nossas contas, queremos incluir esse comportamento
como extenso a todos os objetos do sistema. Como defnir esse mtodo?
public static class Serializer {
// como definir o mtodo???
{
var stringWriter = new StringWriter();
new XmlSerializer(resource.GetType()).Serialize(stringWriter, resource);
return stringWriter.ToString();
}
}
public static string AsXml(this object resource)
public static string AsXml(this resource)
public static string AsXml(object resource)
public static string AsXml(this all resource)
) Defnimos uma extenso a object da seguinte maneira:
namespace Caelum
{
public static class ObjectExtensions
{
public static string ToString(this object resource)
{
var stringWriter = new StringWriter();
new XmlSerializer(resource.GetType()).Serialize(stringWriter, resource);
return stringWriter.ToString();
}
}
}
Ao defnir o using adequado, qual o resultado ao chamar o ToString a seguir?
Captulo - Apndice estendendo comportamentos atravs de mtodos extras - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
using Caelum;
Conta conta = new Conta();
MessageBox.Show(conta.ToString());
No compila pois no podemos sobrescrever o mtodo ToString.
Mostra uma verso em xml de nossa conta, ou seja, o C usa o extension method.
Imprime o resultado tradicional do mtodo ToString, ou seja, o C no usa o extension method.
) Dada a classe Conta defnida nos captulos anteriores:
public abstract class Conta
{
public double Saldo { get; protected set; }
// outros mtodos e propriedades da classe Conta
}
E uma classe com um extension method para a conta:
public static class ContaExtensions
{
public static void MudaSaldo (this Conta conta, double novoSaldo)
{
conta.Saldo = novoSaldo;
}
}
Escolha a alternativa com a afrmao verdadeira.
Esse cdigo no compila, pois o Extension Method s pode acessar a interface pblica da Conta.
Ocdigo funciona normalmente, pois o compilador do C trata umextensionmethod como se fosse
um mtodo da Conta e, portanto, o mtodo pode acessar os mtodos e atributos private e protected
da Conta.
O cdigo compila normalmente, porm s podemos usar o MudaSaldo dentro da prpria classe
Conta.
) Sobre o cdigo a seguir:
public abstract class Conta
{
public Cliente Titular { get; set; }
// outros mtodos e atributos da conta
}
public static class ContaExtensions
{
Captulo - Apndice estendendo comportamentos atravs de mtodos extras - Exerccios - Pgina
Material do Treinamento C e Orientao a Objetos
public static void MudaTitular(this Conta conta, this Cliente titular)
{
conta.Titular = titular;
}
}
O que podemos afrmar?
O cdigo no compila, pois o this s pode fcar no primeiro argumento do extension method.
Compila normalmente e podemos usar o MudaTitular como extension method de Conta e de Cli-
ente.
Compila normalmente, porm o mtodo s pode ser usado como extension method de Conta.
) Dadas as classes:
public abstract class Conta
{
public Cliente Titular { get; set; }
// outros mtodos e atributos da Conta
}
public static class ContaExtensions
{
public static void MudaTitular(this Conta c, Cliente titular)
{
c.Titular = titular;
}
}
O que podemos afrmar sobre o cdigo a seguir?
Conta c = new ContaCorrente();
Cliente titular = new Cliente("victor");
ContaExtensions.MudaTitular(c, titular);
Extension Method um mtodo esttico comum e, portanto, o cdigo do exerccio funciona.
O cdigo do exerccio no compila. S podemos usar o MudaTitular como extension method e no
como mtodo esttico.
O cdigo no compila, pois temos um this no primeiro argumento do MudaTitular.
Captulo - Apndice estendendo comportamentos atravs de mtodos extras - Exerccios - Pgina