uso comercial deste material, por favor, consulte a Caelum … · 2020-07-03 · Essa apostila é...
Transcript of uso comercial deste material, por favor, consulte a Caelum … · 2020-07-03 · Essa apostila é...
EstaapostiladaCaelumvisaensinardeumamaneiraelegante,mostrandoapenasoqueénecessárioequandoénecessário,nomomentocerto,poupandoo leitordeassuntosquenãocostumamserde seuinteresseemdeterminadasfasesdoaprendizado.
ACaelumesperaquevocêaproveiteessematerial.Todososcomentários,críticasesugestõesserãomuitobem-vindos.
EssaapostilaéconstantementeatualizadaedisponibilizadanositedaCaelum.Sempreconsulteositeparanovasversõese,aoinvésdeanexaroPDFparaenviaraumamigo,indiqueositeparaqueelepossasemprebaixarasúltimasversões.Vocêpodeconferirocódigodeversãodaapostilalogono naldoíndice.
Baixesempreaversãomaisnovaem:www.caelum.com.br/apostilas
Esse material é parte integrante do treinamento C# e Orientação a Objetos e distribuídogratuitamente exclusivamente pelo site da Caelum. Todos os direitos são reservados à Caelum. Adistribuição, cópia, revenda e utilização paraministrar treinamentos são absolutamente vedadas. Parausocomercialdestematerial,porfavor,consulteaCaelumpreviamente.
SOBREESTAAPOSTILA
1
3
14
20
25
Sumário
1ComoaprenderC#1.1Oqueérealmenteimportante? 1
1.2Sobreosexercícios 1
1.3Tirandodúvidaseindoalém 2
2OqueéC#e.Net2.1UmpoucosobreahistóriadoC#e.Net 3
2.2Máquinavirtual 4
2.3ExecuçãodocódigonaCLReoJIT 5
2.4OambientededesenvolvimentodoC# 6
2.5ExecutandoaplicaçõessemoVisualStudio 6
2.6OprimeiroprogramaemC# 7
2.7Exercícios 11
2.8Oqueaconteceuduranteaexecução? 12
3Variáveisetiposprimitivos3.1Operaçõescomvariáveis 14
3.2TiposPrimitivos 16
3.3Armazenandotextoemvariáveis 17
3.4Documentandoocódigoatravésdecomentários 17
3.5Exercícios 18
4Estruturasdecontrole4.1Tomandodecisõesnocódigo 20
4.2Maissobrecondições 21
4.3Exercíciosopcionais 22
5Estruturasderepetição5.1Repetindoumblocodecódigo 25
5.2Parasabermaisdowhile 26
5.3Parasabermaisincrementoedecremento 26
SumárioCaelum
29
47
57
61
80
5.4Exercícios 27
6Classeseobjetos6.1OrganizandoocódigocomObjetos 29
6.2Extraindocomportamentosatravésdemétodos 32
6.3Devolvendovaloresdedentrodométodo 34
6.4Valorpadrãodosatributosdaclasse 36
6.5Maisumexemplo:Transfere 37
6.6Convençãodenomes 38
6.7Exercícios 45
6.8Composiçãodeclasses 44
6.9Exercícios 45
7EncapsulamentoeModificadoresdeAcesso7.1Encapsulamento 48
7.2Controlandooacessocomproperties 50
7.3SimplificandoadeclaraçãodepropriedadescomAuto-ImplementedProperties 52
7.4Convençãodenomeparaproperty 53
7.5Exercícios 54
7.6Parasabermais:VisibilidadeInternal 55
8Construtores8.1Múltiplosconstrutoresdentrodaclasse 57
8.2Parasabermais—Initializer 59
8.3Exercícios 59
9IntroduçãoaoVisualStudiocomWindowsForm9.1IntroduçãopráticaaosatalhosdoVisualStudio 64
9.2AclasseConvert 68
9.3Operaçõesnaconta:saqueedepósito 69
9.4Controlandoonomedaaçãodeumbotão 71
9.5RenomeandoVariáveis,MétodoseClassescomoVisualStudio 72
9.6Parasabermais—organizandooformuláriocomLabeleGroupBox 73
9.7ResumodosatalhosdoVisualStudio 75
9.8Exercícios 76
9.9Parasabermais—tiposimplícitoseapalavraVAR 76
9.10ExercíciosOpcionais 77
10Herança10.1ReaproveitandocódigocomaHerança 81
10.2Reaproveitandoaimplementaçãodaclassebase 83
CaelumSumário
91
100
109
113
120
125
134
141
149
10.3Polimorfismo 84
10.4Exercícios 87
10.5Parasabermais—oqueéherdado? 89
11Trabalhandocomarrays11.1Parasabermais—inicializaçãodeArrays 92
11.2Exercícios 98
11.3OrganizandoascontascomoComboBox 96
11.4Exercícios 98
12Cadastrodenovascontas12.1UtilizandooAdicionaContanoloaddoformulário 104
12.2Exercícios 106
13Classesabstratas13.1Exercícios 111
14Interfaces14.1Exercícios 116
15Métodoseatributosestáticos15.1ExercíciosOpcionais 122
15.2Parasabermaisclassesestáticas 123
16Exceções16.1Retornodométodoparacontrolarerros 125
16.2Controlandoerroscomexceções 126
16.3Tratandomúltiplasexceções 128
16.4Exercícios 131
17Namespaces17.1Parasabermais-Declaraçãodenamespaceaninhados 136
17.2Parasabermais-Aliasparanamespaces 137
17.3Exercícios 139
18ClasseObject18.1Implementandoacomparaçãodeobjetos 141
18.2MelhorandoaimplementaçãodoEqualscomois 144
18.3IntegrandooObjectcomoComboBox 145
18.4Exercícios 146
19Trabalhandocomlistas
SumárioCaelum
153
166
176
185
190
19.1Facilitandootrabalhocomcoleçõesatravésdaslistas 149
19.2Exercícios 151
20Lidandocomconjuntos20.1Otimizandoabuscaatravésdeconjuntos 153
20.2ConjuntosOrdenadoscomoSortedSet 155
20.3Ainterfacedetodososconjuntos 156
20.4Comparaçãoentrelistaseconjuntos 156
20.5Exercícios 163
20.6BuscasrápidasutilizandoDicionários 160
20.7Iterandonodicionário 161
20.8Exercícios 163
21LINQeLambda21.1FiltrosutilizandooLINQ 166
21.2Simplificandoadeclaraçãodolambda 167
21.3OutrosmétodosdoLINQ 168
21.4UtilizandooLINQcomoutrostipos 169
21.5Melhorandoasbuscasutilizandoasintaxedequeries 169
21.6Parasabermais—projeçõeseobjetosanônimos 170
21.7Exercícios 171
21.8OrdenandocoleçõescomLINQ 174
21.9Exercícios-Ordenação 175
22System.IO22.1Leituradearquivos 176
22.2Escrevendoemarquivos 178
22.3Gerenciandoosarquivoscomousing 179
22.4Exercícios 180
22.5Parasabermais—ondecolocarosarquivosdaaplicação 183
23Manipulaçãodestrings23.1Exercícios 186
24Apêndice—estendendocomportamentosatravésdemétodosextras24.1Exercícios 191
Versão:24.8.9
CaelumSumário
CAPÍTULO1
Muitoslivros,aopassardoscapítulos,mencionamtodososdetalhesdalinguagem,juntamentecomseusprincípios básicos. Isso acaba criandomuita confusão, em especial porque o estudante não conseguediferenciarexatamenteoqueéessencialaprendernoinício,daquiloquepodeserdeixadoparaestudarmaistarde.
Se uma classe abstrata deve ou não ter aomenos ummétodo abstrato, se oif somente aceita
argumentosbooleanosetodososdetalhessobreclassesinternas,realmentenãodevemserpreocupaçõesparaaquelecujoobjetivoprimárioéaprenderC#.Essetipodeinformaçãoseráadquiridacomotempoenãoénecessárianoinício.
Nestecurso,separamosessasinformaçõesemquadrosespeciais, jáquesãoinformaçõesextra.Ouentão,apenascitamosemalgumexercícioedeixamosparaoleitorprocurarinformaçõesadicionais,sefordeseuinteresse.
Porfim,faltamencionaralgosobreaprática,quedeveser tratadaseriamente: todososexercíciossãomuito importanteseosdesafiospodemser feitosapóso términodocurso.Dequalquermaneira,recomendamosaosalunosestudarememcasaepraticarembastantecódigoevariações.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
COMOAPRENDERC#
1.1OQUEÉREALMENTEIMPORTANTE?
Agoraéamelhorhoradeaprenderalgonovo
1.2SOBREOSEXERCÍCIOS
1COMOAPRENDERC# 1
Os exercícios do curso variam, de práticos até pesquisas na internet, ou mesmo consultas sobreassuntosavançadosemdeterminadostópicos,paraincitaracuriosidadedoaprendiznatecnologia.
Existe também, emdeterminados capítulos, uma série de desafios.Eles focammais no problemacomputacionalquenalinguagem,porémsãoumaexcelenteformadetreinarasintaxee,principalmente,familiarizaroalunocomasbibliotecaspadrãodoC#,alémdeproporcionarumganhonavelocidadededesenvolvimento.
Paratirardúvidasdeexercícios,oudeC#emgeral,recomendamosofórumdoGUJRespostas:
http://www.guj.com.br
Lásuadúvidaserárespondidaprontamente.OGUJfoifundadopordesenvolvedoresdaCaelumehojecontacommaisdeummilhãodemensagens.
Oprincipalrecursooficialparaencontrardocumentação,tutoriaiseatémesmolivrossobre.NETeC#,éaMicrosoftDevelopersNetwork,ouMSDN:
https://msdn.microsoft.com
DestacamosaseçãodetutoriaisdeC#(eminglês),noendereço:
https://www.microsoft.com/net/tutorials/csharp/getting-started
HátambémfórunsoficiaisemportuguêsnaMSDN:
https://social.msdn.microsoft.com/Forums/pt-br/home
Foraisso,sinta-seàvontadeparaentraremcontatocomseuinstrutorparatirartodasasdúvidasquesurgiremduranteocurso.
Seoquevocêestábuscandosãolivrosdeapoio,sugerimosconheceraeditoraCasadoCódigo:
https://www.casadocodigo.com.br/
ACaelumofereceoutrocursodeC#/.NET,oFN-23,quetrazaaplicaçãodoC#naWeb:
https://www.caelum.com.br/
Hátambémcursosonlinequevãoajudá-loairalém,commuitainteraçãocomosinstrutores:
https://www.alura.com.br/
1.3TIRANDODÚVIDASEINDOALÉM
2 1.3TIRANDODÚVIDASEINDOALÉM
CAPÍTULO2
EntenderumpoucodahistóriadoC#edo.Netéessencialparaenxergarosmotivosquealevaramaosucesso.
Nofinaldadécadade1990aMicrosofttinhadiversastecnologiaselinguagensdeprogramaçãopararesolvermuitosproblemasdiferentes.Todavezqueumprogramadorprecisavamigrarparaumanovalinguagem, era necessário aprender tanto a nova linguagemquanto suas bibliotecas e conceitos. Parasolucionaressesproblemas,aMicrosoftrecorreuàlinguagemJava.
OJavaagradouosengenheirosdaMicrosoftpoiscomelapodíamosconstruirprogramasqueeramindependentesdoambientedeexecução,alémdepossuirdiversasbibliotecascomsoluçõesprontasparadiversos problemas. Para lançar produtos baseados no Java, a Microsoft assinou um acordo delicenciamentocomaSunparautilizaroJavaemambienteWindows.
Porém, a linguagem Java possuía um grave problema: ela não se comunicava bem com asbibliotecasdecódigonativo(códigodemáquina)quejáexistiam.Pararesolverisso,aMicrosoftdecidiucriar a sua própria implementação do Java chamado J++, que possuía extensões proprietárias queresolviamo problema de comunicação como código nativo existente. Para o desenvolvimento dessanovaimplementaçãodoJava,aMicrosoftcontratouumengenheirochamadoAndersHejlsberg,umdosprincipaisnomesportrásdoDelphi.
OJ++eraumaversãoda linguagemJavaquesópodiaserexecutadanoambienteMicrosoft.Seucódigonãopodia ser executadoemmaisnenhumambiente Java,oqueviolavao licenciamento feitocomaSune,porisso,aMicrosoftfoiprocessada.Umadasmaisconhecidasbatalhasjudiciaisdaépoca.
SemoJ++,aMicrosoft foiobrigadaa repensarsuaestratégiasobrecomo lidarcomasdiferenteslinguagens e tecnologias utilizadas internamente. A empresa começou a trabalhar em um novaplataformaque seria abasede todas as suas soluções,queposteriormente foi chamadade .Net.Essenovo ambiente de desenvolvimento da Microsoft foi desde o início projetado para trabalhar comdiversas linguagens de programação, assim diversas linguagens diferentes compartilhariam omesmoconjunto de bibliotecas. Com isso, para um programador migrar de uma linguagem para outra eleprecisariaapenasaprenderalinguagemsemsepreocuparcomasbibliotecaseAPIs.
Alémde uma plataforma aMicrosoft tambémprecisava de uma linguagemde programação.Um
OQUEÉC#E.NET
2.1UMPOUCOSOBREAHISTÓRIADOC#E.NET
2OQUEÉC#E.NET 3
novo projeto de linguagem de programação foi iniciado, o projeto COOL (C-like Object OrientedLanguage).AndersHejlsbergfoiescolhidocomoengenheirochefedessenovoprojeto.COOLteveseudesignbaseadoemdiversasoutraslinguagensdomercadocomoJava,C,C++,Smalltalk,DelphieVB.Aideiaeraestudarosproblemasexistenteseincorporarsoluções.
Em 2002, o projetoCOOL foi lançado como linguagemC# 1.0, junto com o ambiente .Net 1.0.Atualmente, a linguagem C# está em sua versão 7.0, e o .Net na versão 4.7, tendo evoluído comexpressivavelocidade,adotandonovidadesnasuasintaxequeadiferenciarambastantedoJavaeoutrasconcorrentes.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Em uma linguagem de programação como C e Pascal, temos a seguinte situação quando vamoscompilarumprograma:
O código fonte é compilado para código de máquina específico de uma plataforma e sistemaoperacional.Muitasvezesoprópriocódigofonteédesenvolvidovisandoumaúnicaplataforma!
Esse código executável (binário) resultante será executado pelo sistema operacional e, por essemotivo, ele deve saber conversar com o sistema operacional em questão. Isto é, temos um códigoexecutáveldiferenteparacadasistemaoperacionaldiferente.
Precisamosreescreverummesmopedaçodaaplicaçãoparadiferentessistemasoperacionais,jáqueelesnãosãocompatíveis.
OC#utilizaoconceitodemáquinavirtual.Entreosistemaoperacionaleaaplicaçãoexisteumacamadaextraresponsávelpor"traduzir"—masnãoapenasisso—oquesuaaplicaçãodesejafazerparaasrespectivaschamadasdosistemaoperacionalondeelaestárodandonomomento.
EditoraCasadoCódigocomlivrosdeumaformadiferente
2.2MÁQUINAVIRTUAL
4 2.2MÁQUINAVIRTUAL
Reparequeumamáquinavirtualéumconceitobemmaisamploqueodeuminterpretador.Comoopróprio nome diz, uma máquina virtual é como um "computador de mentira": tem tudo que umcomputador tem. Em outras palavras, ela é responsável por gerenciar memória, threads, a pilha deexecuçãoetc.
Sua aplicação roda sem nenhum envolvimento com o sistema operacional! Sempre conversandoapenascomamáquinavirtualdoC#,aCommonLanguageRuntime(CLR).ACLRéoambientedeexecuçãopara todasas linguagensdaplataforma.Net,nãoapenasparaoC#.Certamente issonãofoiuma revolução.O Java trouxe esse conceito para omercado e já haviamuitas linguagens com essesrecursos,apesardequeeramencontradasmaisnomeioacadêmico.
O CLR isola totalmente a aplicação do sistema operacional. Se uma aplicação rodando no CLRtermina abruptamente, ela não afetará as outrasmáquinas virtuais e nemo sistemaoperacional.Essacamadadeisolamentotambéméinteressantequandopensamosemumservidorquenãopodesesujeitararodarcódigoquepossainterferirnaboaexecuçãodeoutrasaplicações.
Comoamáquinavirtualdevetrabalharcomdiversaslinguagensdeprogramaçãodiferentes,aCLRnão pode executar diretamente o código do C#, ela precisa executar uma linguagem intermediáriacomumatodasaslinguagensdaplataforma.Net,aCIL(CommonIntermediateLanguage).ParageraroCILque seráexecutadopelaCLR,precisamospassarocódigoC#porumcompiladorda linguagem,comooprogramacsc.exe.Ocompiladorlêoarquivocomocódigofontedoprogramaeotraduzpara
ocódigointermediárioqueseráexecutadopelamáquinavirtual.
COMMONLANGUAGEINFRASTRUCTURE
Ainfraestruturanecessáriaparaexecutaroscódigosescritosparaaplataforma.NetéchamadadeCLI (Common Language Infrastructure). A CLI engloba amáquina virtual do C# (CLR), alinguagemintermediária(CIL)eostiposbaseutilizadosnosprogramas.
ParaexecutarmosumaaplicaçãoC#,precisamospassarocódigoCILdoprogramaparaaCLR,amáquina virtual do .Net. A CLR por sua vez precisa executar o código da aplicação no sistemaoperacionaldousuárioe,paraisso,precisaemitirocódigodemáquinacorretoparaoambienteemqueoprogramaestásendoexecutado.MasaCLRnãointerpretaoCILdoprograma,issoseriamuitolento,ao invés disso, quando o programaC# é carregado namemória, aCLR converte automaticamente ocódigoCILparacódigodemáquina, esseprocessoé feitoporumcompiladorJust inTime (JIT) daCLR.
EssecarregamentoutilizandooJITfazcomqueocódigoescritonalinguagemC#executecomo
2.3EXECUÇÃODOCÓDIGONACLREOJIT
2.3EXECUÇÃODOCÓDIGONACLREOJIT 5
desempenhomáximo,omesmodeumprogramaescritoemlinguagensquecompilamdiretamenteparaocódigodemáquina,mascomavantagemdeexecutarnoambienteintegradodo.Net.
NessecursoescreveremostodoocódigoutilizandooVisualStudioComunity,aversãogratuitadaferramenta de desenvolvimento de aplicações, que é distribuída pela própria Microsoft. Apesar dasexplicações serem feitas com base na versão comunity, tudo funcionará damesma forma dentro dasversõespagasdaferramenta.
OVisualStudioComunitypodeserencontradonosite:
https://www.visualstudio.com/pt-br/downloads/
AversãoqueutilizaremosnaapostilaéaVisualStudioComunity2017.
Durantea instalaçãodoVisualStudio,o .NetFramework tambémseráautomaticamente instaladoemsuamáquina,entãoelaestaráprontaexecutarasaplicaçõesescritasemC#.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Comovimosanteriormente,paraexecutarmosumaaplicaçãoC#precisamosdamáquinavirtualdalinguagemalémdasbibliotecasdo.NetFramework.AoinstalarmosoVisualStudio,todoesseambientede execução de programas é automaticamente instalado em nossas máquinas, mas e se quisermosexecutaroprogramaemumcomputadorquenãotenhaoVisualStudioinstalado,ocomputadordeumcliente,porexemplo?
Nessecasoprecisamosinstalarapenasoambientedeexecuçãonocomputadordocliente.ParaissopodemosutilizarumpacotedeinstalaçãofornecidopelaprópriaMicrosoft,essessãoos.NetFramework
2.4OAMBIENTEDEDESENVOLVIMENTODOC#
JáconheceoscursosonlineAlura?
2.5EXECUTANDOAPLICAÇÕESSEMOVISUALSTUDIO
6 2.4OAMBIENTEDEDESENVOLVIMENTODOC#
Redistributable.Opacotedeinstalaçãoparaaúltimaversãodo.NetFramework(4.5.1lançadaem2013)podeserencontradanoseguintesite:
http://www.microsoft.com/en-us/download/details.aspx?id=40779
C#EMOUTROSAMBIENTES
Podemos também executar o código C# dentro de ambientes não windows utilizandoimplementaçõeslivresdoCommonLanguageInfrastructure.UmaimplementaçãodoambientedeexecuçãoparaambientesnãoWindowséoMono:
http://www.mono-project.com/Main_Page
Agora que já entendemos o funcionamento da linguagem C#, vamos começar a desenvolver aprimeiraaplicaçãoutilizandooVisualStudio.ParacriarmosumprogramaC#utilizandooVisualStudioprecisamosinicialmentedeumnovoprojeto.
DentrodoVisualStudio2017,aperteoatalhoCtrl+Shift+Nparaabriroassistentedecriação
denovoprojeto.
2.6OPRIMEIROPROGRAMAEMC#
2.6OPRIMEIROPROGRAMAEMC# 7
Nocantoesquerdodajaneladoassistentedecriaçãodenovoprojeto,podemosescolheralinguagemde programação que desejamos utilizar, escolha a opçãoVisualC#. Como tipo de projeto escolha aopçãoWindowsFormApplication, com isso estamos criando um novo projeto de interface gráficautilizandooC#.
No canto inferior da janela, podemos escolher o nome do projeto alémda pasta emque ele seráarmazenado.UtilizaremosOiMundocomonomedessenovoprojeto.
Queremos inicialmentecolocarumbotãono formulárioque,quandoclicado, abriráumacaixademensagemdoWindows.
Paracolocarmosobotãonoformulário,precisamosabrirumanovajaneladoVisualStudiochamadaToolbox, que fica no canto esquerdo da janela do formulário. O Toolbox também pode ser abertoutilizando-seoatalhoCtrl+Alt+X.Dentrodajanelado"Toolbox",nogrupo"CommonControls",
cliquenocomponente"Button"earraste-oparaoformulário.
8 2.6OPRIMEIROPROGRAMAEMC#
Agora dê um duplo clique no botão que acabamos de adicionar para programarmos o que deveacontecerquandoobotãoforclicado.OVisualStudioabriráocódigodoformulário.Nãosepreocupecomtodoocódigocomplicadoqueestáescritonessearquivo,entenderemososignificadodecadaumadessaslinhasmaisafrentenocurso.
2.6OPRIMEIROPROGRAMAEMC# 9
usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.Text;usingSystem.Windows.Forms;
namespaceform{publicpartialclassForm1:Form{publicForm1(){InitializeComponent();}
privatevoidbutton1_Click(objectsender,EventArgse){
}}}
Otrechodecódigoquenosinteressanomomentoé:
privatevoidbutton1_Click(objectsender,EventArgse){
}
Todocódigoqueforcolocadodentrodaschavesseráexecutadoquandoobotãoforclicado.
No clique do botão, queremos executar o comando que mostra uma caixa de mensagens para ousuário.
MessageBox.Show(mensagem)
NoC#,todocomandodeveserterminadopelocaractere";".Portanto,ocódigoparamostraracaixademensagemficadaseguinteforma:
MessageBox.Show(mensagem);
Queremos que, ao clicar no botão, a mensagem Hello World seja exibida em uma caixa de
mensagens.Então,utilizaremososeguintecódigo:
privatevoidbutton1_Click(objectsender,EventArgse){MessageBox.Show(HelloWorld);}
Como a mensagem é somente um texto, o compilador do C# nos força a colocá-la entre aspasduplas.Portanto,ocódigodocliquedobotãoficaráassim:
privatevoidbutton1_Click(objectsender,EventArgse){MessageBox.Show("HelloWorld");
10 2.6OPRIMEIROPROGRAMAEMC#
}
Ocódigocompletofica:
usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.Text;usingSystem.Windows.Forms;
namespaceform{publicpartialclassForm1:Form{publicForm1(){InitializeComponent();}
privatevoidbutton1_Click(objectsender,EventArgse){MessageBox.Show("HelloWorld");}}}
Nãosepreocupecomaslinhasdecódigoquenãoforamexplicadas.Entenderemosoqueelasfazemduranteocurso.
Aperte"F5"paraexecutarocódigodoformulário.Aoclicarno"button1",oresultadodeveseralgoparecidocomaimagemaseguir:
2.7EXERCÍCIOS
2.7EXERCÍCIOS 11
1. Qualamensagemqueseráexibidanacaixadetextocriadapeloseguintecódigo?
MessageBox.Show("CursodeC#daCaelum");
HelloWorld
CursodeC#daCaelum
OláMundo
Caelum
Nenhumadasopções
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
Vimos que quando apertamos a tecla F5 do teclado dentro do Visual Studio, nosso programa éexecutado.Agoravamosentenderoqueaconteceu.
Quando pedimos para o Visual Studio executar uma aplicação, ele chama o compilador dalinguagem C# passando os arquivos de texto que contém o código da aplicação (código fonte doprograma). Caso o código fonte não tenha nenhum erro de sintaxe, o compilador gera o códigointermediário (CIL, Common Intermediate Language) que é entendido pela máquina virtual dalinguagem C#, a CLR (Common Language Runtime). O código CIL é colocado em um arquivoexecutável (arquivo com extensão .exe) dentro da pasta do projeto. Esse arquivo que é resultado dacompilaçãodoprogramaéchamadodeAssemblydentrodalinguagemC#.
Depoisdacompilação,oVisualStudioexecutaoassemblygeradonamáquinavirtualdoC#.ACLRporsuavezcarregaocódigoCILquefoigeradopelocompiladoreoexecutanosistemaoperacional,masseaCLRinterpretasseocódigoCILparalinguagemdemáquina,odesempenhodoC#nãoseriamuito bom, e por isso, quando um programa C# é carregado pela CLR ele já é automaticamente
VocêpodetambémfazerocursodatadessaapostilanaCaelum
2.8OQUEACONTECEUDURANTEAEXECUÇÃO?
12 2.8OQUEACONTECEUDURANTEAEXECUÇÃO?
convertidopara linguagemdemáquinaporumprocessoconhecidocomoJIT(Just-in-time).EntãonoC#,ocódigosempreéexecutadocomomesmodesempenhodocódigodemáquina.
2.8OQUEACONTECEUDURANTEAEXECUÇÃO? 13
CAPÍTULO3
Namaioriadosprogramasqueescrevemos,nãoestamosinteressadosemapenasmostrarumacaixademensagensparaousuário.Queremostambémarmazenareprocessarinformações.
Emumsistemabancário,porexemplo,estaríamosinteressadosemarmazenarosaldodeumacontaeonomedocorrentista.Paraarmazenaressesdados,precisamospedirparaoC# reservar regiõesdememória que serão utilizadas para armazenar informações.Essas regiões dememória são conhecidascomovariáveis.
As variáveis guardam informações de um tipo específico. Podemos, por exemplo, guardar umnúmerointeirorepresentandoonúmerodaconta,umtextopararepresentaronomedocorrentistaouumnúmerorealpararepresentarosaldoatualdaconta.Parautilizarumavariável,devemosprimeiramentedeclará-lanotextodoprograma.
Nadeclaraçãodeumavariável,devemosdizerseutipo(inteiro,textooureal,porexemplo)e,alémdisso,qualéonomequeusaremosparareferenciá-lanotextodoprograma.Paradeclararumavariáveldotipointeiroquerepresentaonúmerodeumaconta,utilizamososeguintecódigo:
intnumeroDaConta;
Repareno;nofinaldalinha.Comoadeclaraçãodeumavariáveléumcomandodalinguagem
C#,precisamosdo;paraterminá-lo.
Alémdo tipoint (para representar inteiros), temos tambémos tiposdouble efloat (para
númerosreais),string(paratextos),entreoutros.
Depois de declarada, uma variável pode ser utilizada para armazenar valores. Por exemplo, seestivéssemos interessados em guardar o valor 1 na variável numeroDaConta que declaramos
anteriormente,utilizaríamososeguintecódigo:
numeroDaConta=1;
Lê-se"numeroDaContarecebe1".Quando,nomomentodadeclaraçãodavariável, sabemosqualseráseuvalor,podemosutilizaraseguintesintaxeparadeclarareatribuirovalorparaavariável.
doublesaldo=100.0;
VARIÁVEISETIPOSPRIMITIVOS
3.1OPERAÇÕESCOMVARIÁVEIS
14 3VARIÁVEISETIPOSPRIMITIVOS
Agoraque já sabemoscomoguardar informaçõesnoprograma,estamos interessadosemexecutaroperaçõesnessesvalores.Podeserinteressanteparaumcorrentistasaberqualseráosaldodesuacontaapósumsaquede10reais.Pararealizaressaoperação,devemossubtrair10reaisdosaldodaconta:
doublesaldo=100.0;saldo=saldo-10.0;
Nessecódigo,estamosguardandonavariávelsaldoovalordaconta100.0(saldoantigo)menos
10.0entãoseuvalorfinalseráde90.0.Damesmaformaquepodemossubtrairvalores,podemos
tambémfazersomas(comooperador+),multiplicações(operador*)edivisões(operador/).
Podemosaindaguardarovalordosaqueemumavariável:
doublesaldo=100.0;doublevalorDoSaque=10.0;saldo=saldo-valorDoSaque;
Depois de realizar o saque, queremosmostrar para o usuário qual é o saldo atual da conta. Paramostrarmosessainformação,utilizaremosnovamenteoMessageBox.Show:
MessageBox.Show("Osaldodacontaapósosaqueé:"+saldo);
Veja que, no código do saque, estamos repetindo o nome da variável saldo dos dois lados daatribuição.Quandotemosessetipodecódigo,podemosutilizarumaabreviaçãodisponibilizadapeloC#,ooperador-=:
doublesaldo=100.0;doublevalorDoSaque=10.0;saldo-=valorDoSaque;
QuandoocompiladordoC#encontraosaldo-=valorDoSaque, essa linhaé traduzidaparaa
formaquevimosanteriormente:saldo=saldo-valorDoSaque.Alémdo-=, temostambémos
operadores+=(parasomas),*=(paramultiplicações)e/=(paradivisões).
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Agoraéamelhorhoradeaprenderalgonovo
3.1OPERAÇÕESCOMVARIÁVEIS 15
Vimos que noC# toda variável possui um tipo, utilizamos o int quando queremos armazenar
valores inteiros edouble para números reais. Agora vamos descobrir quais são os outros tipos de
variáveisdoC#.
Ostiposlistadosnessatabelasãoconhecidoscomotiposprimitivosouvaluetypes da linguagemC#. Toda vez que atribuímos um valor para uma variável de um tipo primitivo, o C# copia o valoratribuídoparadentrodavariável.
AgoraqueconhecemosostiposprimitivosdalinguagemC#,vamosvercomoéqueelesinteragemdentro de uma aplicação. Suponha que temos um código que declara uma variável do tipo inteiro edepoistentacopiarseuconteúdoparaumavariávellong:
intvalor=1;longvalorGrande=valor;
Nessecaso,comootamanhodeumavariávellongémaiordoqueodeumavariávelint,oC#
sabe que podemos copiar o seu conteúdo sem perder informações e, por isso, esse é um código quecompilasemnenhumerro.Agoravamostentarcopiarointparaumavariáveldotiposhort:
intvalor=1;shortvalorPequeno=valor;
3.2TIPOSPRIMITIVOS
16 3.2TIPOSPRIMITIVOS
Nessecódigo, tentamoscopiaroconteúdodeumavariávelmaiorparadentrodeumade tamanhomenor.Essacópiapodeserperigosapoisovalorqueestánavariáveldotipointpodenãocaberna
variávelshort e,por isso,ocompiladordoC#geraumerrodecompilaçãoquando tentamos fazer
essaconversão.
Para forçarmos o compilador do C# a fazer uma conversão perigosa, precisamos utilizar umaoperaçãodoC#chamadacastingfalandoparaqualtipoqueremosfazeraconversão.
intvalor=1;shortvalorPequeno=(short)valor;
Alémdostiposprimitivos,oC#tambémpossuiumtipoespecíficoparaarmazenartextos.Notipostring,podemosguardarqualquervalorquesejadelimitadoporaspasduplas,porexemplo:
stringmensagem="MinhaMensagem";MessageBox.Show(mensagem);
Podemosjuntarovalordeduasvariáveisdotipostringutilizandoooperador+dalinguagem.A
somadestringséumaoperaçãoconhecidacomoconcatenação.
stringmensagem="Olá";stringnome="victor";
MessageBox.Show(mensagem+nome);
Esse código imprime o texto Olá victor em uma caixa de mensagens. Podemos utilizar a
concatenaçãoparaadicionaroconteúdodequalquervariávelemumastring:
intidade=25;stringmensagem="suaidadeé:"+idade;
MessageBox.Show(mensagem);
Essesegundocódigoimprimeotextosuaidadeé:25.
QuandoqueremosdocumentarosignificadodealgumcódigodentrodeumprogramaC#,podemosutilizarcomentários.Parafazermosumcomentáriodeumalinha,utilizamoso//.Tudoque estiver
depoisdo//éconsideradocomentárioe,porisso,ignoradopelocompiladordalinguagem.
doublesaldo=100.0;//Issoéumcomentárioeseráignoradopelocompilador
Muitas vezes precisamos escrever diversas linhas de comentários para, por exemplo, documentarumalógicacomplexadaaplicação.Nessescasospodemosutilizarocomentáriodemúltiplaslinhasqueéinicializadoporum/*eterminadopelo*/.Tudoqueestiverentreaaberturaeofechamentodo
3.3ARMAZENANDOTEXTOEMVARIÁVEIS
3.4DOCUMENTANDOOCÓDIGOATRAVÉSDECOMENTÁRIOS
3.3ARMAZENANDOTEXTOEMVARIÁVEIS 17
comentárioéignoradopelocompiladordalinguagem:
/*Issoéumcomentáriodemúltiplaslinhas*/
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Faça o código dos exercícios do capítulo dentro de botões no formulário do projeto inicial, cadaexercíciodeveficarnaaçãodeumbotãodiferente.
1. Crie3variáveiscomasidadesdosseusmelhoresamigose/oufamiliares.Algocomo:
intidadeJoao=10;intidadeMaria=25;
Emseguida,pegueessas3idadesecalculeamédiadelas.ExibaoresultadoemumMessageBox.
2. Oqueacontececomocódigoabaixo?
intpi=3.14;
Ocódigocompila,e"pi"guardaonúmero3
Ocódigocompila,e"pi"guarda3.14(inteirospodemguardarcasasdecimais)
Ocódigonãocompila,pois3.14não"cabe"dentrodeuminteiro
3. Executeotrechodecódigoaseguir.Oqueacontececomele?
doublepi=3.14;intpiQuebrado=(int)pi;MessageBox.Show("piQuebrado="+piQuebrado);
Repareo(int).Estamos"forçando"aconversãododoubleparauminteiro.
EditoraCasadoCódigocomlivrosdeumaformadiferente
3.5EXERCÍCIOS
18 3.5EXERCÍCIOS
QualovalordepiQuebradonessecaso?
3.14
0
3
4. (Opcional) No colegial, aprendemos a resolver equações de segundo grau usando a fórmula deBhaskara.Afórmulaéassim:
delta=b*b-4*a*c;a1=(-b+raiz(delta))/(2*a);a2=(-b-raiz(delta))/(2*a);
Crie um programa com três variáveis inteiras,a,b,c, com quaisquer valores. Depois crie 3
variáveisdouble,delta,a1,a2,comafórmulaanterior.
Imprimaa1ea2emumMessageBox.
Dica:Paracalcularraizquadrada,useMath.Sqrt(variavel).Nãoseesqueçaquenãopodemos
calculararaizquadradadenúmerosnegativos.
3.5EXERCÍCIOS 19
CAPÍTULO4
Voltandoparanossoexemplodeaplicaçãobancária,queremospermitirumsaquesomenteseovaloraserretiradoformenorouigualaosaldodaconta,ouseja,seosaldodacontaformaiorouigualaovalordosaque,devemospermitiraoperação,docontrárionãopodemospermitirosaque.Precisamosfazerexecuçãocondicionaldecódigo.
NoC#,podemosexecutarcódigocondicionalutilizandoaconstruçãoif:
if(condicao){//Essecódigoseráexecutadosomenteseacondiçãoforverdadeira}
Nonossoexemplo,queremosexecutar a lógicade saqueapenas seo saldo formaiorou igual aovalordosaque:
doublesaldo=100.0;doublevalorSaque=10.0;if(saldo>=valorSaque){//códigodosaque.}
O código do saque deve diminuir o saldo da conta e mostrar uma mensagem para o usuárioindicandoqueosaqueocorreucomsucesso:
doublesaldo=100.0;doublevalorSaque=10.0;if(saldo>=valorSaque){saldo=saldo-valorSaque;MessageBox.Show("Saquerealizadocomsucesso");}
Repare que, se a conta não tiver saldo suficiente para o saque, o usuário não é avisado. Entãoestamos na seguinte situação: "Se a conta tiver saldo suficiente, quero fazer o saque, senão, queromostraramensagemSaldoInsuficienteparaousuário".Parafazerisso,podemosusaroelsedoC#:
if(saldo>=valorSaque){//códigodosaque}else
ESTRUTURASDECONTROLE
4.1TOMANDODECISÕESNOCÓDIGO
20 4ESTRUTURASDECONTROLE
{MessageBox.Show("SaldoInsuficiente");}
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Repare na expressão que passamos para o if: saldo >= valorSaque. Nele, utilizamos o
operador"maiorouigual".Alémdele,existemoutrosoperadoresdecomparaçãoquepodemosutilizar:maior (>),menor (<),menor ou igual (<=), igual (==) e diferente (!=). Podemos tambémnegar umacondiçãodeumifutilizandoooperador!nafrentedacondiçãoqueseránegada.
No capítulo anterior, vimos que um valor tem um tipo associado em C#: 10 é um int ,
"mensagem"éumastring.Damesmaforma,aexpressãosaldo>=valorSaquetambémtemum
tipo associado: o tipobool, que pode assumir os valores true (verdadeiro) ou false (falso).
Podemosinclusiveguardarumvalordessetiponumavariável:
boolpodeSacar=(saldo>=valorSaque);
Tambémpodemosrealizaralgumasoperaçõescomvaloresdotipobool.Podemos,porexemplo,
verificarseduascondiçõessãoverdadeirasaomesmotempousandoooperador&&(AND)parafazer
umelógico:
boolrealmentePodeSacar=(saldo>=valorSaque)&&(valorSaque>0);
QuandoprecisamosdeumOUlógico,utilizamosooperador||:
//essacondiçãoéverdadeirase(saldo>=valorSaque)fortrue//ouse(valorSaque>0)forverdadeiro.boolrealmentePodeSacar=(saldo>=valorSaque)||(valorSaque>0);
Assim,podemosconstruircondiçõesmaiscomplexasparaumif.Porexemplo,podemosusara
variávelrealmentePodeSacardeclaradanoifqueverificaseoclientepodesacarounão:
JáconheceoscursosonlineAlura?
4.2MAISSOBRECONDIÇÕES
4.2MAISSOBRECONDIÇÕES 21
if(realmentePodeSacar){//códigodosaque}else{MessageBox.Show("SaldoInsuficiente");}
1. Qualéamensagemeovalordavariávelsaldoapósaexecuçãodoseguintecódigo?
doublesaldo=100.0;doublevalorSaque=10.0;if(saldo>=valorSaque){saldo-=valorSaque;MessageBox.Show("Saquerealizadocomsucesso");}else{MessageBox.Show("SaldoInsuficiente");}
mensagem:Saquerealizadocomsucesso;saldo:90.0
mensagem:SaldoInsuficiente;saldo90.0
mensagem:Saquerealizadocomsucesso;saldo:100.0
mensagem:SaldoInsuficiente;saldo100.0
mensagem:Saquerealizadocomsucesso;saldo:10.0
2. Qualéamensagemeovalordavariávelsaldoapósaexecuçãodoseguintecódigo?
doublesaldo=5.0;doublevalorSaque=10.0;if(saldo>=valorSaque){saldo-=valorSaque;MessageBox.Show("Saquerealizadocomsucesso");}else{MessageBox.Show("SaldoInsuficiente");}
mensagem:Saquerealizadocomsucesso;saldo:-5.0
mensagem:SaldoInsuficiente;saldo-5.0
mensagem:Saquerealizadocomsucesso;saldo:5.0
mensagem:SaldoInsuficiente;saldo5.0
4.3EXERCÍCIOSOPCIONAIS
22 4.3EXERCÍCIOSOPCIONAIS
mensagem:Saquerealizadocomsucesso;saldo:10.0
3. Emalgunscasos,podemostermaisdeduasdecisõespossíveis.Obancopode,porexemplo,decidirquecontascomsaldomenorqueR$1000pagam1%detaxademanutenção,contascomsaldoentreR$1000eR$5000pagam5%econtascomsaldomaiorqueR$5000pagam10%.
Pararepresentaressetipodesituação,podemosusaroelseifdoC#,quefuncionaemconjunto
comoifquejáconhecemos.Vejacomoficariaasituaçãodescritaanteriormente:
doubletaxa;if(saldo<1000){taxa=0.01;}elseif(saldo<=5000){taxa=0.05;}else{taxa=0.1;}
OC#vaiprocessarascondiçõesnaordem,atéencontrarumaquesejasatisfeita.Ouseja,nasegundacondiçãodocódigo,sóprecisamosverificarquesaldoémenorouigualaR$5000,poisseoC#
chegarnessacondiçãoéporqueelenãoentrounoprimeiroif, istoé, sabemosqueosaldo é
maiorouigualaR$1000nesseponto.
Combasenisso,qualvaiseramensagemexibidapelocódigoseguinte?
doublesaldo=500.0;if(saldo<0.0){MessageBox.Show("Vocêestánonegativo!");}elseif(saldo<1000000.0){MessageBox.Show("Vocêéumbomcliente");}else{MessageBox.Show("Vocêémilionário!");}
"Vocêestánonegativo!"
"Vocêéumbomcliente"
Nenhumamensagem
"Vocêémilionário!"
"Vocêéumbomcliente",seguidade"Vocêémilionário!"
4.3EXERCÍCIOSOPCIONAIS 23
4. Uma pessoa só pode votar em eleições brasileiras se ela for maior que 16 anos e for cidadãbrasileira.Crieumprogramacomduasvariáveis,intidade,boolbrasileira,efaçacomque
oprogramadigaseapessoaestáaptaavotarounão,deacordocomosdadosnasvariáveis.
5. Crie umprogramaque tenhaumavariáveldoublevalorDaNotaFiscal e, de acordo com esse
valor,oimpostodevesercalculado.Asregrasdecálculosão:
Seovalorformenorouiguala999,oimpostodeveserde2%Seovalorestiverentre1000e2999,oimpostodeveserde2.5%Seovalorestiverentre3000e6999,oimpostodeveserde2.8%
Seformaiorouiguala7000,oimpostodeveserde3%
ImprimaoimpostoemumMessageBox.
6. (Desafio)Dadooseguintecódigo:
intvalor=15;stringmensagem="";if(valor>10){mensagem="Maiorquedez";}else{mensagem="Menorquedez;}MessageBox.Show(mensagem);
Existeumaformade fazero ifdessecódigouma linhasó, semusar apalavra if e else.Pesquisesobreissoetentefazer.
24 4.3EXERCÍCIOSOPCIONAIS
CAPÍTULO5
De volta ao exemplo da aula anterior, suponha agora que o cliente dessemesmo banco queira saberquanto ele ganhará, ao final de 1 ano, caso ele invista um valor. O investimento paga 1% do valorinvestidoaomês.
Porexemplo,seoclienteinvestirR$1000,00,aofinalde12meses,teráporvoltadeR$1126,82:noprimeiromês,R$1000,00+R$1000,001%=R$1010,00;nosegundomês,R$1010,00+R$1010,001% =R$ 1020,10; e assim por diante. Ou seja, para calcular o quanto ele terá ao final de um ano,podemosmultiplicarovalorinvestido12vezespor1%.
Pararesolvermosesseproblema,precisamosfazerusodeumaestruturadecontrolequerepeteumdeterminadoblocodecódigoatéqueumacondiçãosejasatisfeita.Essaestruturarecebeonomedeloop.
ParafazerumloopnoC#,utilizaremos,inicialmente,ainstruçãofor.Oforéumainstruçãoque
possuitrêspartes:
Aprimeira parte é a inicialização, na qual podemos declarar e inicializar uma variável que seráutilizadanofor;
A segunda parte é a condição do loop. Enquanto a condição do loop for verdadeira, o loopcontinuaráexecutando;Aterceiraparteéaatualização,naqualpodemosatualizarasvariáveisquesãoutilizadaspelofor.
Cadaumadaspartesdoforéseparadaporum;.
for(inicialização;condição;atualização){//Essecódigoseráexecutadoenquantoacondiçãoforverdadeira}
Vejaocódigoaseguir,porexemplo,emqueusamosumforquerepetiráocálculo12vezes:
doublevalorInvestido=1000.0;for(inti=1;i<=12;i+=1){valorInvestido=valorInvestido*1.01;}MessageBox.Show("Valorinvestidoagoraé"+valorInvestido);
ESTRUTURASDEREPETIÇÃO
5.1REPETINDOUMBLOCODECÓDIGO
5ESTRUTURASDEREPETIÇÃO 25
Vejaquenossoforcomeça inicializandoavariáveli com1e repeteo códigodedentrodele
enquantoovalordeiformenorouiguala12,ouseja,elesóparanomomentoemqueiformaior
doque12.Evejaque,acadaiteraçãodesseloop,ovalordeicresce(i+=1).Nofim,ocódigode
dentrodoforserárepetido12vezes,comoprecisávamos.
Omesmoprogramapoderiaserescritoutilizando-seumwhile,emvezdeumfor:
doublevalorInvestido=1000.0;inti=1;while(i<=12){valorInvestido=valorInvestido*1.01;i+=1;}MessageBox.Show("Valorinvestidoagoraé"+valorInvestido);
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
No C# quando utilizamos o while, a condição do loop é checada antes de todas as voltas
(iterações)dolaço,masesequiséssemosgarantirqueocorpodolaçosejaexecutadopelomenosumavez?Nessecaso,podemosutilizarumoutrotipodelaçodoC#queéodowhile:
do{//corpodoloop}while(condição);
Comodowhile a condiçãodo loop só é checadano fimdavolta, ou seja, o corpodo loop é
executado e depois a condição é checada, então o corpo do do...while sempre é executado pelo
menosumavez.
VocêpodetambémfazerocursodatadessaapostilanaCaelum
5.2PARASABERMAISDOWHILE
5.3PARASABERMAISINCREMENTOEDECREMENTO
26 5.2PARASABERMAISDOWHILE
Quandoqueremosincrementarovalordeumavariávelinteiraemumaunidade,vimosquetemos2opções:
intvalor=1;
valor=valor+1;//ouvalor+=1;
Porém,comoincrementarovalordeumavariáveléumaatividadecomumnaprogramação,oC#nosofereceooperador++pararealizaressetrabalho:
intvalor=1;valor++;
Temosaindaooperador--querealizaodecrementodeumavariável.
1. Qualéovalorexibidonoseguintecódigo:
inttotal=2;for(inti=0;i<5;i+=1){total=total*2;}MessageBox.Show("Ototalé:"+total);
256
64
128
512
2. FaçaumprogramaemC#queimprimaasomadosnúmerosde1até1000.
3. FaçaumprogramaemC#queimprimatodososmúltiplosde3,entre1e100.
Parasaberseumnúmeroémúltiplode3,vocêpodefazerif(numero%3==0).
4. (Opcional) Escreva um programa em C# que some todos os números de 1 a 100, pulando osmúltiplosde3.OprogramadeveimprimiroresultadofinalemumMessageBox.
Qualoresultado?
5. (Opcional)EscrevaumprogramaemC#queimprimetodososnúmerosquesãodivisíveispor3oupor4entre0e30.
6. (Opcional)FaçaumprogramaemC#queimprimaosfatoriaisde1a10.
5.4EXERCÍCIOS
5.4EXERCÍCIOS 27
Ofatorialdeumnúmeronénn-1n-2...atén=1.
Ofatorialde0é1
Ofatorialde1é(0!)*1=1
Ofatorialde2é(1!)*2=2
Ofatorialde3é(2!)*3=6
Ofatorialde4é(3!)*4=24
Façaumforqueinicieumavariáveln(número)como1efatorial(resultado)como1evariande1até10:
intfatorial=1;for(intn=1;n<=10;n++){
}
7. (Opcional)FaçaumprogramaemC#queimprimaosprimeirosnúmerosdasériedeFibonacciatépassarde100.AsériedeFibonacciéaseguinte:0,1,1,2,3,5,8,13,21etc...Paracalculá-la,oprimeiroelementovale0,osegundovale1,daípordiante,on-ésimoelementovaleo(n-1)-ésimoelementosomadoao(n-2)-ésimoelemento(ex:8=5+3).
8. (Opcional)Façaumprogramaqueimprimaaseguintetabela,usandoforsencadeados:
124369481216nn*2n*3....n*n
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
28 5.4EXERCÍCIOS
CAPÍTULO6
Neste momento, queremos representar diversas contas em nosso banco. Uma conta bancária égeralmentecompostaporumnúmero,nomedotitularesaldo.Podemosguardaressasinformaçõesemvariáveis:
intnumeroDaConta1=1;stringtitularDaConta1="JoaquimJosé";doublesaldoDaConta1=1500.0;
Pararepresentaroutroscorrentistas,precisamosdenovasvariáveis:
intnumeroDaConta2=2;stringtitularDaConta2="SilvaXavier";doublesaldoDaConta2=2500.0;
Vejaque,comoasinformaçõesdascontasestãoespalhadasemdiversasvariáveisdiferentes,émuitofácilmisturarmosessasinformaçõesdentrodocódigo.Alémdisso,imaginequeantesdeadicionarmosacontanaaplicaçãoprecisamosfazerumavalidaçãodoCPFdotitular.Nessecasoprecisaríamoschamaruma função que executa essa validação, mas como podemos garantir que essa validação sempre éexecutada?
Esses pontos listados são alguns dos problemas do estilo de programação procedural. Quandotrabalhamoscomprogramaçãoprocedural,osdadosdaaplicaçãoficamseparadosdaimplementaçãodaslógicasdenegócioe,alémdisso,émuitodifícilgarantirasvalidaçõesdosdadosdaaplicação.
Paracomeçarmoscomaorientaçãoaobjetos,vamosinicialmentepensarquaissãoasinformaçõesquedescrevemumadeterminadaConta.Toda conta bancária possui umnúmero, titular e saldo.Pararepresentarmosacontacomessasinformaçõesdentrodoprojeto,noC#,precisamoscriarumaclasse.DentrodoC#adeclaraçãodaclasseéfeitautilizando-seapalavraclassseguidadonomedaclassequequeremosimplementar:
classConta{
}
OcódigodaclasseConta,porconvenção,deveficardentrodeumarquivocomomesmonomeda
classe,entãoaclasseContaserácolocadoemarquivochamadoConta.cs.
CLASSESEOBJETOS
6.1ORGANIZANDOOCÓDIGOCOMOBJETOS
6CLASSESEOBJETOS 29
Dentro dessa classe queremos armazenar as informações que descrevem as contas, fazemos issodeclarandovariáveisdentrodaclasse,essasvariáveissãoosatributos:
classConta{intnumero;stringtitular;doublesaldo;}
Porém,paraqueocódigodaaplicaçãopossalereescrevernessesatributos,precisamosdeclará-losutilizandoapalavrapublic:
classConta{//numero,titularesaldosãoatributosdoobjetopublicintnumero;publicstringtitular;publicdoublesaldo;}
Parautilizarmosaclassequecriamosdentrodeumaaplicaçãowindowsform,precisamoscriarumanovacontanocódigodoformulário,fazemosissoutilizandoainstruçãonewdoC#:
//códigodoformulárioprivatevoidbutton1_Click(objectsender,EventArgse){newConta();}
QuandoutilizamosonewdentrodocódigodeumaclasseestamospedindoparaoC#criaruma
novainstânciadeContanamemória,ouseja,oC#alocarámemóriasuficienteparaguardartodasas
informaçõesdaContadentrodamemóriadaaplicação.
Além disso, o new possuimais uma função, devolver a referência, uma seta que aponta para oobjeto emmemória, que será utilizada para manipularmos a Conta criada. Podemos guardar essa
referênciadentrodeumavariáveldotipoConta:
//códigodoformulárioprivatevoidbutton1_Click(objectsender,EventArgse){Contac=newConta();}
Namemóriadaaplicaçãoteremosumasituaçãoparecidacomailustradanaimagemaseguir:
30 6.1ORGANIZANDOOCÓDIGOCOMOBJETOS
VejaqueaclassefuncionacomoumareceitaqueensinaqualéoformatodeumaContadentroda
aplicação.AContaquefoicriadanamemóriapelooperadornewéchamadadeinstânciaouobjeto.
E agora para definirmos os valores dos atributos que serão armazenados naConta, precisamos
acessaroobjetoquevivenamemória.Fazemosissoutilizandoooperador.doC#,informandoqualéoatributo que queremos acessar. Para, por exemplo, guardarmos o valor 1 comonúmero da conta quecriamos,utilizamosocódigoaseguir:
//códigodoformulárioprivatevoidbutton1_Click(objectsender,EventArgse){Contac=newConta();c.numero=1;}
Com esse código, estamos navegando na referência armazenada na variável c, e acessando o
campo número do objeto Conta que vive na memória. Dentro desse campo colocamos o valor 1.
PodemosfazeromesmoparaosoutroscamposdaConta:
privatevoidbutton1_Click(objectsender,EventArgse){Contac=newConta();c.numero=1;c.titular="victor";c.saldo=100;}
Depoisdaexecuçãodessecódigo,teremosaseguintesituaçãonamemóriadaaplicação:
6.1ORGANIZANDOOCÓDIGOCOMOBJETOS 31
Veja que, quando utilizamos um objeto para guardar informações, todos os atributos ficamagrupados dentro de um único objeto na memória, e não espalhados dentro de diversas variáveisdiferentes.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Agoraqueconseguimoscriaraprimeiracontadaaplicação,vamostentarfazeralgumasoperações.Aprimeiraoperaçãoquequeremosimplementaréaoperaçãodetirardinheirodaconta.Paraisso,comovimosnocapítuloanterior,podemosutilizarooperador-=doC#:
Contac=newConta();c.numero=1;c.titular="victor";c.saldo=100;//acontaterminacomsaldode50.0
Agoraéamelhorhoradeaprenderalgonovo
6.2EXTRAINDOCOMPORTAMENTOSATRAVÉSDEMÉTODOS
32 6.2EXTRAINDOCOMPORTAMENTOSATRAVÉSDEMÉTODOS
c.saldo-=50.0;
Masoqueaconteceriasetentássemostirarmais100.0dessaconta?
c.saldo-=100.0;
Ao executarmos essa segunda operação, a conta terminará com saldo de -50.0, porém nesse
sistemaascontasnãopodemficarcomsaldonegativo!Portanto,antesde tirarmosdinheirodaconta,precisamosverificarseelapossuisaldosuficiente.
if(c.saldo>=100.0){c.saldo-=100.0;}
Repare que teremos que copiar e colar essa verificação em todos os pontos da aplicação emquedesejamos fazer um saque,mas o que aconteceria se fosse necessário cobrar uma taxa em todos ossaques?Teríamosquemodificartodosospontosemqueocódigofoicopiado.SeriamaisinteressanteisolaressecódigodentrodeumcomportamentodaConta.
Alémdeatributos,osobjetos tambémpodempossuirmétodos.Osmétodos sãoblocosdecódigoqueisolamlógicasdenegóciodoobjeto.EntãopodemosisolaralógicadosaquedentrodeummétodoSacadaclasseConta.
ParadeclararummétodochamadoSacanaclasseConta,utilizamosaseguintesintaxe:
classConta{//declaraçãodosatributos
publicvoidSaca(){//Implementaçãodométodo}}
DentrodessemétodoSaca,colocaremosocódigodalógicadesaque.
publicvoidSaca(){if(c.saldo>=100.0){c.saldo-=100.0;}}
Porém, nesse código temos dois problemas: não podemos utilizar a variável c , pois ela foi
declaradanoformulárioenãodentrodométodoeovalordosaqueestáconstante.
NessemétodoSaca, queremos verificar o saldo da conta em que ométodo foi invocado. Para
acessarmos a referência em que um determinadométodo foi chamado, utilizamos a palavra this.
Entãoparaacessarmososaldodaconta,podemosutilizarthis.saldo:
6.2EXTRAINDOCOMPORTAMENTOSATRAVÉSDEMÉTODOS 33
publicvoidSaca(){if(this.saldo>=100.0){this.saldo-=100.0;}}
PodemosutilizaroSacadentrodoformuláriocomoseguintecódigo:
Contac=newConta();//inicializaasinformaçõesdacontac.saldo=100.0;
//AgorachamaométodoSacaquefoidefinidonaclassec.Saca();
Agoravamosresolveroproblemadovalorfixodosaque.Quandoqueremospassarumvalorparaummétodo,precisamospassaressevalordentrodosparêntesesdachamadadométodo:
Contac=newConta();//inicializaasinformaçõesdacontac.saldo=100.0;
//AgorachamaométodoSacaquefoidefinidonaclassec.Saca(10.0);
PararecebermosovalorquefoipassadonachamadadoSaca,precisamosdeclararumargumentonométodo.Oargumentoéumavariáveldeclaradadentrodosparêntesesdométodo:
publicvoidSaca(doublevalor){if(this.saldo>=valor){this.saldo-=valor;}}
Ummétodopodeterqualquernúmerodeargumentos.Precisamosapenassepararadeclaraçãodasvariáveiscomumavírgula.
AgoraquecolocamosométodoSacadentrodaclasseConta,nãoprecisamosreplicarocódigode
validaçãodosaqueemtodosospontosdocódigo,podemossimplesmenteutilizarométodocriado,alémdisso, seprecisarmosmodificar a lógicado saque,podemos simplesmenteatualizarocódigodaquelemétodo,umúnicopontodosistema.
Masdaformaquefoi implementado,ousuáriodessemétodonãosabeseosaquefoiounãobemsucedido.Precisamosfazercomqueométododevolvaumvalorbooleanoindicandoseaoperaçãofoiounãobemsucedida.Devolveremostruecasoaoperaçãosejabemsucedidaefalsecasocontrário.
Quandoummétododevolveumvalor,otipodovalordevolvidodeveficarantesdonomedométodo
6.3DEVOLVENDOVALORESDEDENTRODOMÉTODO
34 6.3DEVOLVENDOVALORESDEDENTRODOMÉTODO
emsuadeclaração.Quandoummétodonãodevolvevaloralgum,utilizamosotipovoid.
//EstamosdeclarandoqueométododevolveumvalordotipoboolpublicboolSaca(doublevalor){//implementaçãodométodo}
Dentrodaimplementaçãodométodo,devolvemosumvalorutilizamosapalavrareturnseguidadovalorquedeveserdevolvido.EntãoaimplementaçãodoSacaficadaseguinteforma:
publicboolSaca(doublevalor){if(this.saldo>=valor){this.saldo-=valor;returntrue;}else{returnfalse;}}
Quando o C# executa um return, ele imediatamente devolve o valor e sai do método, então
podemossimplificaraimplementaçãodoSacapara:
publicboolSaca(doublevalor){if(this.saldo>=valor){this.saldo-=valor;returntrue;}returnfalse;}
Noformuláriopodemosrecuperarovalordevolvidoporummétodo.
Contac=newConta();//inicializaosatributos
//Seacontativersaldosuficiente,deuCertoconteráovalortrue//senão,elaconteráfalsebooldeuCerto=c.Saca(100.0);
if(deuCerto){MessageBox.Show("Saquerealizadocomsucesso");}else{MessageBox.Show("SaldoInsuficiente");}
Oupodemosutilizaroretornodométododiretamentedentrodoif:
Contac=newConta();//inicializaosatributos
6.3DEVOLVENDOVALORESDEDENTRODOMÉTODO 35
if(c.Saca(100.0)){MessageBox.Show("Saquerealizadocomsucesso");}else{MessageBox.Show("SaldoInsuficiente");}
Agoraque terminamosde implementara lógicadesaquedaconta,vamos tambémimplementarométododedepósito.Essemétodonãodevolveránenhumvalorereceberáumdoublecomoargumento:
publicvoidDeposita(doublevalor){this.saldo+=valor;}
Noformulárioprincipaldaaplicação,podemosinicializarosaldoinicialcomométodoDeposita:
Contac=newConta();c.Deposita(100.0);
Nesse código estamos tentando depositar 100 reais em uma conta que acabou de ser criada e ométodoDepositatentasomaros100.0novalorinicialdoatributosaldodaconta.Masqualéovalor
inicialdeumatributo?
QuandodeclaramosumavariávelnoC#,elacomeçacomumvalor indefinido, logonãopodemosutilizá-laenquantoseuvalornãoforinicializado,porémalinguagemtrataosatributosdeumaclassedeforma diferenciada. Quando instanciamos uma classe, todos os seus atributos são inicializados paravalores padrão. Valores numéricos são inicializados para zero, o bool é inicializado para false e
atributosqueguardamreferênciassãoinicializadosparaareferênciavazia(valornulldoC#).
Então,noexemplo,quandodepositamos100reaisnacontarecém-criada,estamossomando100nosaldoinicialdaconta,queézero,edepoisguardandooresultadodevoltanosaldodaconta.
Podemos mudar o valor padrão de um determinado atributo colocando um valor inicial em suadeclaração.Parainicializarmosacontacomsaldoinicialde100reaisaoinvésdezero,podemosutilizaroseguintecódigo:
classConta{publicdoublesaldo=100.0;
//outrosatributosemétodosdaclasse}
Agoratodacontacriadajácomeçarácomumsaldoinicialde100.0.
6.4VALORPADRÃODOSATRIBUTOSDACLASSE
36 6.4VALORPADRÃODOSATRIBUTOSDACLASSE
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Agoravamostentarimplementaraoperaçãodetransferênciadedinheiroentreduascontas.DentrodaclasseContacriaremosmaisummétodochamadoTransfere,essemétodoreceberáovalorda
transferênciaeascontasqueparticiparãodaoperação:
publicvoidTransfere(doublevalor,Contaorigem,Contadestino){//implementaçãodatransferência}
Mas será que realmente precisamos receber as duas contas como argumento do métodoTransfere?Vamosvercomoessemétodoseráutilizadodentrodocódigodoformulário:
Contavictor=newConta();//inicializaçãodacontavictor.saldo=1000;
Contaguilherme=newConta();//inicializaçãodaconta
//Agoravamostransferirodinheirodacontadovictorparaadoguilhermevictor.Transfere(10.0,victor,guilherme);
Reparequenousodométodoestamosrepetindoduasvezesavariávelvictor,porémissonãoé
necessário. Podemos utilizar o this para acessar a conta de origem dentro do método, então na
verdadeométodoTransfereprecisareceberapenasacontadedestino:
publicvoidTransfere(doublevalor,Contadestino){//implementaçãodatransferência}
Antes de tirarmos dinheiro da conta de origem (this), precisamos verificar se ela tem saldo
EditoraCasadoCódigocomlivrosdeumaformadiferente
6.5MAISUMEXEMPLO:TRANSFERE
6.5MAISUMEXEMPLO:TRANSFERE 37
suficiente, somentenessecasoqueremossacarodinheirodacontadeorigemedepositarnacontadedestino:
publicvoidTransfere(doublevalor,Contadestino){if(this.saldo>=valor){this.saldo-=valor;destino.saldo+=valor;}}
Masessecomportamentodeverificarseaconta temsaldosuficienteantesderealizarosaqueéocomportamentodométodoSacaquefoiimplementadoanteriormente,alémdisso,somarumvalorno
saldoéaoperaçãoDepositadaconta.Portanto,podemosutilizarosmétodosSaca eDeposita
existentesparaimplementaroTransfere:
publicvoidTransfere(doublevalor,Contadestino){if(this.Saca(valor)){destino.Deposita(valor);}}
Quando criamos uma classe, é importante lembrarmos que seu código será lido por outrosdesenvolvedoresdaequipee,porisso,érecomendávelseguirpadrõesdenomenclatura.
Quandocriamosumaclasse,arecomendaçãoéutilizaroPascalCasingparanomearaclasse:
Seonomedaclasseécompostoporumaúnicapalavra,colocamosaprimeiraletradessapalavraemmaiúscula(contasetornaConta);
Seonomeécompostopordiversaspalavras,juntamostodasaspalavrascolocandoaprimeiraletradecadapalavraemmaiúscula(segurodevidasetornaSeguroDeVida).
Nocasodonomedemétodos,aconvençãotambéméutilizaroPascalCasing(SacaeDeposita,porexemplo).
Paraargumentosdemétodos,arecomendaçãoéutilizaroPascalCasingporémcomaprimeiraletraemminúscula(valorDoSaque,porexemplo),umaconvençãochamadaCamelCasing.
VocêpodeencontrarasrecomendaçõesdaMicrosoftnesselink:http://msdn.microsoft.com/en-us/library/ms229040(v=vs.110).aspx
6.6CONVENÇÃODENOMES
6.7EXERCÍCIOS
38 6.6CONVENÇÃODENOMES
1. Oqueumaclassetem?
Sóosatributosdeumaentidadedosistema;
Sóatributosousómétodosdeumaentidadedosistema;
Sóosmétodosdeumaentidadedosistema;
Atributosemétodosdeumaentidadedosistema.
2. VamoscriaraclasseContadentrodoprojetoinicialutilizandooVisualStudio.
No Visual Studio clique com o botão direito no nome do projeto e selecione a opção Add >
Class...
DentrodajanelaabertapeloVisualStudio,precisamosdefinirqualéonomedaclassequequeremoscriar.EscolhaonomeConta:
6.6CONVENÇÃODENOMES 39
Depoisdecolocaronomedaclasse, cliquenobotãoAdd.Com isso, oVisualStudio criará um
novoarquivodentrodoProjeto,oConta.cs.TodoocódigodaclasseContaficarádentrodesse
arquivo:
classConta{//Ocódigodaclasseficaaquidentro!}
Agora declare os seguintes atributos dentro da Conta:saldo (double), titular (string) e
numero(int).
3. QualdoscomandosaseguirinstanciaumanovaConta?
Contaconta=Conta();
Contaconta=newConta();
Contaconta=Conta.new();
4. Levandoemconsideraçãoocódigo:
Contac=newConta();c.saldo=1000.0;
Qualdaslinhasaseguiradiciona200reaisnessesaldo?
saldo+=200;
c.saldo+=200;
Contac.saldo+=200;
40 6.6CONVENÇÃODENOMES
Conta.saldo+=200;
5. AgoravamostestaraclasseContaqueacabamosdecriar.Coloqueumnovobotãonoformulário
da aplicação. Dê um duplo clique nesse botão para definirmos qual será o código executado nocliquedobotão.
privatevoidbutton1_Click(objectsender,EventArgse){//açãodobotãoaqui.}
Dentrodocódigodessebotão,instancieumanovaContaetentefazeralgunstestespreenchendoe
mostrandoseusatributosatravésdoMessageBox.Show.Porexemplo:
privatevoidbutton1_Click(objectsender,EventArgse){ContacontaVictor=newConta();contaVictor.titular="victor";contaVictor.numero=1;contaVictor.saldo=100.0;
MessageBox.Show(contaVictor.titular);}
Tente fazer testes com diversas contas e veja que cada instância de conta possui seus própriosatributos.
6. AgoravamosimplementarmétodosnaclasseConta.ComeçaremospelométodoDeposita,esse
métodonãodevolvenadaedeve receberumargumentodo tipodouble que é o valor que será
depositadonaConta.Asuaclassedeveficarparecidacomaquesegue:
//dentrodoarquivoConta.cs
classConta{//declaraçãodosatributos
publicvoidDeposita(doublevalor){//oquecolocaraquinaimplementação?}}
DepoisdeimplementarométodoDeposita, implemente tambémométodoSaca.Ele também
nãodevolvevaloralgumerecebeumdoublequeéovalorqueserásacadodaconta.
7. Agoravamostestarosmétodosqueacabamosdecriar.Naaçãodobotãoqueutilizamosparatestaraconta,vamosmanipularosaldoutilizandoosmétodosDepositaeSaca:
privatevoidbutton1_Click(objectsender,EventArgse){ContacontaVictor=newConta();contaVictor.titular="victor";contaVictor.numero=1;
6.6CONVENÇÃODENOMES 41
contaVictor.Deposita(100);MessageBox.Show("Saldo:"+contaVictor.saldo);contaVictor.Saca(50.0);MessageBox.Show("Saldo:"+contaVictor.saldo);}
Tente fazer depósitos e saques em várias instâncias diferentes deConta, repare que dentro dos
métodosavariávelthispossuiovalordareferênciaemqueométodofoiinvocado.
8. Qualasaídadocódigoaseguir:
Contamauricio=newConta();mauricio.saldo=2000.0;
Contaguilherme=newConta();guilherme.saldo=5000.0;
mauricio.saldo-=200.0;guilherme.saldo+=200.0;
MessageBox.Show("mauricio="+mauricio.saldo);MessageBox.Show("guilherme="+guilherme.saldo);
mauricio=2200.0eguilherme=4800.0
mauricio=2200.0eguilherme=5200.0
mauricio=1800.0eguilherme=5000.0
mauricio=1800.0eguilherme=5200.0
9. Qualasaídadocódigoaseguir?
Contamauricio=newConta();mauricio.numero=1;mauricio.titular="Mauricio";mauricio.saldo=100.0;
Contamauricio2=newConta();mauricio2.numero=1;mauricio2.titular="Mauricio";mauricio2.saldo=100.0;
if(mauricio==mauricio2){MessageBox.Show("Ascontassãoiguais");}else{MessageBox.Show("Ascontassãodiferentes");}
Ascontassãoiguais
Ascontassãodiferentes
Nãoémostradonenhumamensagem
42 6.6CONVENÇÃODENOMES
10. Qualasaídadocódigoaseguir:
Contamauricio=newConta();mauricio.saldo=2000.0;
Contacopia=mauricio;copia.saldo=3000.0;
MessageBox.show("mauricio="+mauricio.saldo);MessageBox.show("copia="+copia.saldo);
mauricio=2000.0ecopia=3000.0
mauricio=3000.0ecopia=2000.0
mauricio=2000.0ecopia=2000.0
mauricio=3000.0ecopia=3000.0
11. (Opcional) Implemente ométodo Transfere que recebe o valor da transferência e a conta de
destino.FaçacomqueelereutilizeasimplementaçõesdosmétodosSacaeDeposita.
12. (Opcional)Vamos adicionar uma validação nométodo Saca da Conta. Modifique o método
Saca para que ele não realize o saque caso o saldo atual da conta sejamenor do que o valor
recebidocomoargumento.
13. (Opcional)ModifiqueométodoSacacomvalidaçãoparaqueeledevolvaovalortrue casoo
saque tenha sido realizado com sucesso efalse caso contrário.Depoismodifique o código do
botãodetestedacontaparaqueeleutilizeovalordevolvidopelométodoSacaparamostraruma
mensagemparaousuário.Casoosaquesejabemsucedido,queremosmostraramensagem"Saquerealizadocomsucesso",senão,mostraremos"Saldoinsuficiente"
14. (Opcional)AgoraaltereométodoSacadaclasseConta.LimiteovalordosaqueparaR$200,00
casooclientesejamenordeidade.
Lembre-sequeaindaénecessáriovalidarseovalorasersacadoémenorouigualaosaldoatualdoclienteeémaiordoqueR$0,00.
6.6CONVENÇÃODENOMES 43
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Quandoabrimosumacontanobanco,temosquefornecerumasériedeinformações:nome,CPF,RGeendereço.
Vimosquequandoqueremosarmazenarinformaçõesemumaclasse,devemoscriaratributos.Masem qual classe colocar esses novos atributos? Claramente essas informações não pertencem a umaConta.Essesdadospertencemaotitulardaconta,ouseja,essasinformaçõespertencemaoclientedo
banco.
Entãodevemosarmazená-lasemumaclasseCliente.
classCliente{publicstringnome;publicstringcpf;publicstringrg;publicstringendereco;}
Sabemostambémquetodacontaestáassociadaaumcliente,ouseja,acontaguardaumareferênciaaoclienteassociado.
classConta{//outrosatributosdaConta
publicClientetitular;
//comportamentosdaconta}
Agora,quandovamoscriarumaconta,podemostambémcolocarseutitular.
Clientevictor=newCliente();
JáconheceoscursosonlineAlura?
6.8COMPOSIÇÃODECLASSES
44 6.8COMPOSIÇÃODECLASSES
victor.nome="victor";
ContaumaConta=newConta();umaConta.titular=victor;
Vimos também que o atributo titular guarda uma referência(seta) para uma instância de
Cliente (objeto namemória). Logo, a atribuiçãoumaConta.titular=victor está copiando a
referênciadavariávelvictorparaoatributotitular.
PodemosmodificarosatributosdoClienteatravésdareferênciaguardadanoatributotitular
daConta.
Clientevictor=newCliente();victor.nome="victor";
ContaumaConta=newConta();umaConta.titular=victor;
umaConta.titular.rg="12345678-9";
//MostraonomevictorMessageBox.Show(umaConta.titular.nome);
//Mostraotexto12345678-9MessageBox.Show(victor.rg);
1. Crie a classe Cliente contendo os atributos nome (string), rg (string), cpf (string) e
endereco(string).ModifiqueaclasseContaefaçacomqueseuatributotitularsejadotipo
Clienteaoinvésdestring.
Tome cuidado.Após essamodificação não poderemos atribuir o nome do cliente diretamente aoatributotitulardaConta.Paradefinironomedotitular,precisaremosdeumcódigoparecido
comoquesegue:
Contaconta=newConta();Clientecliente=newCliente();conta.titular=cliente;conta.titular.nome="Victor";
2. Qualasaídaqueseráimpressaaoexecutaroseguintetrechodecódigo?
ContaumaConta=newConta();Clienteguilherme=newCliente();guilherme.nome="GuilhermeSilveira";umaConta.titular=guilherme;
MessageBox.Show(umaConta.titular.nome);
GuilhermeSilveira
Serámostradoumacaixademensagemsemnenhumamensagem
6.9EXERCÍCIOS
6.7EXERCÍCIOS 45
Ocódigonãocompila
3. Qualasaídaqueseráimpressaaoexecutaroseguintetrechodecódigo?
ContaumaConta=newConta();Clienteguilherme=newCliente();guilherme.rg="12345678-9";
umaConta.titular=guilherme;umaConta.titular.rg="98765432-1";
MessageBox.Show(guilherme.rg);
98765432-1
12345678-9
rg
Nãoseráimpressonada
4. (Opcional)CriemaisumatributonaclasseClientequeguardaaidadedapessoa.Nonossocaso,
aidadeéumnúmerointeiro.
Tambémcrieumcomportamento(método)comonomeEhMaiorDeIdadenaclasseClienteque
não recebenenhumargumentoe retornaumbooleano indicando seo cliente émaiorde idadeounão.QuandoumapessoaémaiordeidadenoBrasil?
46 6.9EXERCÍCIOS
CAPÍTULO7
Nessemomento, nossa classe Conta possui um numero, saldo e cliente titular, além de
comportamentosquepermitemsacaredepositar:
classConta{publicintnumero;publicdoublesaldo;
publicClientetitular;
publicvoidSaca(doublevalor){this.saldo-=valor;}
publicvoidDeposita(doublevalor){this.saldo+=valor;}}
SedesejamosefetuarumsaqueouumdepósitoemumaContaqualquer,fazemos:
conta.Saca(100.0);conta.Deposita(250.0);
Masoqueaconteceseummembrodaequipefaz:
conta.saldo-=100.0;
Nada nos impede de acessar os atributos diretamente. Em três partes distintas do nosso softwaretemostalcódigo:
//emumarquivoconta.saldo-=100.0;
//emoutroarquivoconta.saldo-=250.0;
//emoutroarquivoconta.saldo-=371.0;
Agoraimaginequeobancomudearegradesaque:agoraacadasaquerealizado,obancocobrará0.10centavos.Ouseja,seousuáriosacar10.0reais,énecessáriotirardesuaconta10.10reais.Temosque alterar todosos pontos denossa aplicaçãoque acessamesse atributo!Masnossabasede código
ENCAPSULAMENTOEMODIFICADORESDEACESSO
7ENCAPSULAMENTOEMODIFICADORESDEACESSO 47
pode ser muito grande e é muito comum esquecermos onde e quem está acessando esse atributo,deixandobugstodavezqueesquecemosdealteraralgumlugar.Setivermosessalinhaespalhada300vezes em nosso sistema, precisaremos encontrar todas essas 300 linhas e fazer a alteração. Muitocomplicadoecustoso!
OqueaconteceriaaousarmosométodoSaca():
//emumarquivoconta.Saca(100.0);
//emoutroarquivoconta.Saca(250.0);
//emoutroarquivoconta.Saca(371.0);
Comorefletiríamosaalteraçãona regradosaquede tirar10centavos?PrecisamosalterarapenasumavezométodoSaca(),aoinvésdealterartodasaslinhasqueacessamoatributodiretamente!
Quando liberamos o acesso aos atributos da classe Conta, estamos permitindo que qualquer
programadorfaçaasuaprópriaimplementaçãonãoseguradalógicadesaquedaformaquequiser.Seamodificaçãodoatributoficasserestritaàclassequeodeclara, todosquequisessemsacaroudepositardinheironacontateriamdefazê-loatravésdemétodosdaclasse.Nessecaso,searegradesaquemudarnofuturo,modificaremosapenasométodoSaca.
Na orientação a objetos, esconder os detalhes de implementação de uma classe é um conceitoconhecido como encapsulamento. Como os detalhes de implementação da classe estão escondidos,todooacessodeveserfeitoatravésdeseusmétodospúblicos.NãopermitimosaosoutrossaberCOMOaclassefazotrabalhodela,mostrandoapenasOQUÊelafaz.
Vejaalinhaconta.Saca(100.0);.Sabemosoquêessemétodofazpeloseunome.Mascomoele
fazotrabalhodelesósaberemosseentrarmosdentrodesuaimplementação.Portanto,ocomportamentoestáencapsuladonessemétodo.
Mas ainda não resolvemos o problema de evitar que programadores façam uso diretamente doatributo.Qualquerumaindapodeexecutarocódigoabaixo:
conta.saldo-=371.0;
Para isso,precisamosesconderoatributo.Queremosdeixá-loprivadoparaquesomenteaprópriaclasseContapossautilizá-lo.Nessecasoqueremosmodificaroacessoaoatributoparaqueelesejaprivado,private:
classConta{
7.1ENCAPSULAMENTO
48 7.1ENCAPSULAMENTO
//outrosatributosaquiprivatedoublesaldo;
publicvoidSaca(doublevalor){this.saldo-=valor;}
publicvoidDeposita(doublevalor){this.saldo+=valor;}}
Atributos e métodos private são acessados apenas pela própria classe. Ou seja, o método
Saca(), por exemplo, consegue fazer alterações nele.Mas outras classes não conseguem acessá-lo
diretamente!Ocompiladornãopermite!
Osatributosdeumaclassesãodetalhesdeimplementação,portantomarcaremostodososatributosdacontacomapalavraprivate:
classConta{privateintnumero;privatedoublesaldo;privateClientetitular;
publicvoidSaca(doublevalor){this.saldo-=valor;}
publicvoidDeposita(doublevalor){this.saldo+=valor;}}
Ótimo.Agoraoprogramadoréforçadoapassarpelosmétodosparaconseguirmanipularosaldo.
Setentarmos,porexemplo,escrevernosaldodaContaapartirdocódigodeumformulário,teremos
umerrodecompilação:
Contac=newConta();//Alinhaabaixogeraumerrodecompilaçãoc.saldo=100.0;
Mas agora temos outro problema. Se quisermos exibir o saldo não conseguiremos. O private
bloqueiatantoaescrita,quantoaleitura!
7.1ENCAPSULAMENTO 49
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
VimosquepodemosproibiroacessoexternoaumatributoutilizandooprivatedoC#,masoprivatetambém bloqueia a leitura do atributo, logo para recuperarmos seu valor, precisamos de um novométododentrodaclassequenosdevolveráovaloratualdoatributo:
classConta{privatedoublesaldo;
privateintnumero;
//outrosatributosemétodosdaconta
publicdoublePegaSaldo(){returnthis.saldo;}}
Agoraparamostrarmososaldoparaousuário,utilizaríamososeguintecódigo:
Contaconta=newConta();//inicializaaconta
MessageBox.Show("saldo:"+conta.PegaSaldo());
Além disso, a conta precisa de um número, mas como ele foi declarado como private, não
podemosacessá-lodiretamente.Precisaremosdeumnovométodoparafazeressetrabalho:
classConta{privateintnumero;
//outrosatributosemétodosdaconta
publicvoidColocaNumero(intnumero){this.numero=numero;
VocêpodetambémfazerocursodatadessaapostilanaCaelum
7.2CONTROLANDOOACESSOCOMPROPERTIES
50 7.2CONTROLANDOOACESSOCOMPROPERTIES
}}
Paracolocarmosonúmeronaconta,teríamosqueexecutaressecódigo:
Contaconta=newConta();
conta.ColocaNumero(1100);
//utilizaacontanocódigo
VejaquecomissonósconseguimoscontrolartodooacessoaclasseConta,masparaescrevermos
oulermosovalordeumatributoprecisamosutilizarosmétodos.Oidealseriautilizarmosumasintaxeparecidacomadeacessoaatributos,porémcomocontrolequeométodonosoferece.Para resolveresseproblema,oC#nosofereceasproperties(propriedades).
Adeclaraçãodeumapropriedadeéparecidacomadeclaraçãodeumatributo,porémprecisamosfalaroquedeveserfeitonaleitura(get)enaescrita(set)dapropriedade
classConta{privateintnumero;
publicintNumero{get{//códigoparalerapropriedade}
set{//códigoparaescrevernapropriedade}}}
Naleituradapropriedade,queremosdevolverovalordoatributonumerodaConta:
classConta{privateintnumero;
publicintNumero{get{returnthis.numero;}}}
Comisso,podemoslerapropriedadeNumerocomoseguintecódigo:
Contac=newConta();MessageBox.Show("numero:"+c.Numero);
Veja que o acesso ficou igual ao acesso de atributos, porémquando tentamos ler o valor de uma
7.2CONTROLANDOOACESSOCOMPROPERTIES 51
propriedade estamos na verdade executando um bloco de código (get da propriedade) da classe
Conta.Paradefinirmosonúmerodaconta,utilizaremosocódigo:
Contac=newConta();c.Numero=1;
Quandotentamosescreveremumapropriedade,oC#utilizaoblocosetparaguardarseuvalor.
Dentrodoblocoset, o valor que foi atribuído à propriedade fica dentrodeumavariável chamada
value,entãopodemosimplementarosetdaseguinteforma:
classConta{privateintnumero;
publicintNumero{//declaraçãodogetset{this.numero=value;}}}
Podemos também declarar uma propriedade que tem apenas o get, sem o set. Nesse caso,
estamos declarando uma propriedade que pode ser lidamas não pode ser escrita. Com as propertiesconseguimoscontrolarcompletamenteoacessoaosatributosdaclasseutilizandoasintaxedeacessoaosatributos.
Utilizando as properties, conseguimos controlar o acesso às informações da classe, porém, comovimos,declararumapropertyébemtrabalhoso.Precisamosdeumatributoparaguardarseuvalor,alémdisso,precisamosdeclararogeteoset.
Para facilitar a declaração das properties, a partir do C# 3.0, temos as propriedades que sãoimplementadasautomaticamentepelocompilador,asauto-implementedproperties.Paradeclararmosumaauto-implementedpropertyparaexporonúmerodaconta,utilizamososeguintecódigo:
classConta{publicintNumero{get;set;}}
Essecódigofazcomqueocompiladordeclareumatributodotipoint(cujonomesóéconhecido
pelocompilador)egereocódigoparaapropriedadeNumerocomumget eumset que leeme
escrevemnoatributodeclarado.Reparequeaoutilizarmosasauto-implementedproperties,sópodemosacessarovalordoatributodeclaradoatravésdapropriedade.
7.3 SIMPLIFICANDO A DECLARAÇÃO DE PROPRIEDADES COMAUTO-IMPLEMENTEDPROPERTIES
52 7.3SIMPLIFICANDOADECLARAÇÃODEPROPRIEDADESCOMAUTO-IMPLEMENTEDPROPERTIES
Todavezquedeclaramosumauto-implementedproperty,precisamossempredeclararumget e
umsetparaapropriedade,porémpodemoscontrolaravisibilidadetantodogetquantodoset.
Porexemplo,nocasodosaldo,queremospermitirquequalquerumleiaosaldodaconta,porémapenasaprópriacontapodealterá-lo.Nessecaso,utilizamososeguintecódigo:
classConta{//outraspropriedades
//getépúblicoepodeseracessadoporqualquerclasse//setéprivadoeporissosópodeserusadopelaconta.publicdoubleSaldo{get;privateset;}
//restodocódigodaclasse.}
Agoravamosverumcódigoquetentalereescrevernaspropriedadesquedeclaramos:
Contac=newConta();
c.Numero=1;//funcionapoisosetdoNumeroépúblicoMessageBox.Show("numero:"+c.Numero);//funcionapoisogetdoNumeroépúblico
c.Saldo=100.0;//setdoSaldoéprivado,entãotemosumerroMessageBox.Show("saldo"+c.Saldo);//funcionapoisogetdoSaldoépúblico.
Veja que tanto declarando properties explicitamente quanto utilizando as auto-implementedproperties,temosocontroletotalsobrequaisinformaçõesserãoexpostaspelaclasse.
Entãodevemosutilizarpropertiestodavezquequeremosexporalgumainformaçãodaclasse.Nuncadevemosexporatributosdaclasse(utilizandoopublic),poisnuncaqueremosexporosdetalhesde
implementaçãodaclasse.
AconvençãodenomesdefinidaparapropertiesdoC#éamesmaconvençãodenomesutilizadaparaclasses,ouseja,utilizandooPascalCasing(Todasaspalavrasdonomesãoconcatenadasecadapalavratemainicialmaiúscula,porexemplo:numerodobanco=>NumeroDoBanco)
7.4CONVENÇÃODENOMEPARAPROPERTY
7.4CONVENÇÃODENOMEPARAPROPERTY 53
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
1. Qualocomportamentodoatributoabaixo:
publicintNumero{get;privateset;}
Onúmeropodeserlido,masnãopodeseralteradoporoutrasclasses.
Onúmeronãopodeserlido,maspodeseralteradoporoutrasclasses.
Onúmeronãopodenemserlidonemseralteradoporoutrasclasses.
Onúmeropodeserlidoealteradoporoutrasclasses.
2. Sobreocódigoabaixoéválidoafirmarque...
Contac=newConta();doublevalorADepositar=200.0;c.Saldo+=valorADepositar;
Aoperaçãodedepósitofoiimplementadacorretamente.
Aoperaçãodedepósitonãoestáencapsulada,podendogerarproblemasfuturosdemanutenção.
Aoperaçãodedepósitonãoestáencapsulada,facilitandoamanutençãofuturadocódigo.
3. Oqueéencapsulamento?
ÉdeixarbemclaroparatodosCOMOaclassefazotrabalhodela.
ÉautilizaçãodePropertiesemqualquerumadesuasvariações.
Émanipularealteraratributosdiretamente,sempassarporummétodoespecífico.
Seuslivrosdetecnologiaparecemdoséculopassado?
7.5EXERCÍCIOS
54 7.5EXERCÍCIOS
ÉesconderCOMOaclasse/métodofazsuatarefa.Casoaregramude,temosquealterarapenasumpontodocódigo.
4. Qualoproblemadoatributoabaixo:
publicdoubleSaldo{get;set;}
Nenhum.Eleestáencapsulado,afinalusamosProperties.
Aoinvésdepublic,deveríamosusarprivate.
O atributo 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 sejammodificadospelasoutrasclasses.
5. TransformeosatributosdaclasseContaempropriedades.Permitaqueosaldodacontasejalido,
porémnãosejaalteradoforadaclasse,alteretambémocódigodasclassesqueutilizamacontaparaqueelasacessemaspropriedadesaoinvésdosatributosdiretamente.
Quando escrevemos uma aplicação grande, muitas vezes utilizamos bibliotecas que sãodesenvolvidasporoutraspessoas, asDLLs (DynamicLinkLibrary).Emuitas vezes a aplicação
precisacompartilharclassescomadllimportadanocódigo.
QuandodeclaramosumaclassenoC#,porpadrãoela sópodeservistadentrodopróprioprojeto(visívelapenasnoassemblyqueadeclarou),esseéumníveldevisibilidadeconhecidocomointernal.Quandoqueremostrabalharcombibliotecasexternasaoprojeto,nossasclassesprecisamserdeclaradascomavisibilidadepublic:
publicclassAtualizadorDeContas{//Implementaçãodaclasse}
Comessamodificação,aclasseAtualizadorDeContasévisívelinclusiveforadoassemblyque
adeclarou,ouseja,podemosutilizá-laemqualquerpontodocódigo.
DentrodessaclasseAtualizadorDeContas,vamosdeclararummétodochamadoAtualizaque
recebeumaContacomoargumento.
publicclassAtualizadorDeContas{publicvoidAtualiza(Contaconta){
}}
7.6PARASABERMAIS:VISIBILIDADEINTERNAL
7.6PARASABERMAIS:VISIBILIDADEINTERNAL 55
Comoesseéummétodopúblicodentrodeumaclassepública,elepodeserutilizadoemqualquerponto do código, inclusive em outros assemblies. Porém se a classe Conta for uma classe com
visibilidadeinternal, teremos ummétodo que pode ser visto em todos os pontos do código, que
recebe um argumento visível apenas dentro do assembly que o declarou, ou seja, temos uma
inconsistêncianasvisibilidades.
Quando o compilador do C# detecta uma inconsistência de visibilidade, ele gera um erro decompilação avisando quais são os métodos e classes que estão inconsistentes. Para corrigirmos oproblema de inconsistência do exemplo do AtualizadorDeContas , precisamos declarar a classe
Contacomopublic:
publicclassConta{//implementaçãodaclasse}
Ou alternativamente, podemos deixar a classe AtualizadorDeContas ou ométodo Atualiza
comvisibilidadeinternal:
//internaléavisibilidadepadrãoparaaclasse,//portantoapalavrainternaléopcionalinternalclassAtualizadorDeContas{//implementaçãodaclasse}
56 7.6PARASABERMAIS:VISIBILIDADEINTERNAL
CAPÍTULO8
Comoquevimosnoscapítulosanteriores,nósprecisamoslembrardecolocaronomeapóscriarmosumnovoclienteemnossosistema.Issopodeservistonocódigoaseguir:
Clienteguilherme=newCliente();guilherme.Nome="Guilherme";
Eseesquecermosdechamarasegundalinhadessecódigo,teremosumclientesemnome.Mas,seráquefazsentidoexistirumclientesemnome?
Paraevitarisso,aoconstruirnossoobjetotemosqueobrigarodesenvolvedorafalarqualonomedoCliente.Istoé,queremossercapazesdealterarocomportamentodaconstruçãodoobjeto.
Queremosdefinirumnovocomportamentoquedirácomoseráconstruídooobjeto.Algocomo:
Clienteguilherme=newCliente("GuilhermeSilveira");
Note que esse comportamento que desejamos lembra um comportamento normal, passandoargumentos,mas com a característica especial de ser quem constrói um objeto. Esse comportamentorecebeonomedeconstrutor.Ecomodefini-lo?Similarmenteaumcomportamentoqualquer:
classCliente{//OutrosatributosdaclasseClientepublicstringNome{get;set;}
publicCliente(stringnome){this.Nome=nome;}}
Vimosquequandocriamosumconstrutornaclasse,oC#usaoconstrutorcriadoparainicializaroobjeto,porémoqueacontecequandonãotemosnenhumconstrutornaclasse?Quandoumaclassenãotemnenhumconstrutor,oC#colocaumconstrutorpadrãodentrodaclasse.Esseconstrutornãorecebeargumentosenãoexecutanenhumaação,ouseja,umconstrutorquenãorecebenenhumargumentoetemocorpovazio.
Na seção anterior definimos um construtor dentro da classe cliente que inicializa a propriedade
CONSTRUTORES
8.1MÚLTIPLOSCONSTRUTORESDENTRODACLASSE
8CONSTRUTORES 57
nome,masesequiséssemosinicializartambémaidadedoClienteduranteaconstruçãodoobjeto?
Nessecaso,precisaríamosdeumconstrutoradicionalnaclasseCliente:
classCliente{publicstringNome{get;set;}
publicintIdade{get;set;}
//construtorquesórecebeonomepublicCliente(stringnome){this.Nome=nome;}//construtorquerecebeonomeeaidadepublicCliente(stringnome,intidade){this.Nome=nome;this.Idade=idade;}}
Veja que definimos duas versões diferentes do construtor da classe, uma que recebe apenas astringnomeeoutraquerecebestringnomeeintidade.Quandocolocamosdiversasversões
doconstrutordentrodeumaclasse,estamosfazendoumasobrecargadeconstrutores.
VALORPADRÃOPARAOSPARÂMETROS
NoC#, ao invés de fazermos sobrecarga de construtores para podermos passar informaçõesadicionaisnacriaçãodoobjeto,podemosutilizarosparâmetrosopcionaiscomvalorespadrão.
Você pode ler sobre os parâmetros opcionais no blog da caelum:http://blog.caelum.com.br/parametros-opcionais-e-nomeados-do-c/
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Agoraéamelhorhoradeaprenderalgonovo
58 8.1MÚLTIPLOSCONSTRUTORESDENTRODACLASSE
Vimosquepodemosutilizarumconstrutorparapedirinformaçõesobrigatóriasparaaclasse.Mas,por exemplo, temos a classeCliente e apenas seu nome é obrigatório, então podemos pedir essa
informaçãonoconstrutordaclasse.
Clientecliente=newCliente("VictorHarada");
MasoclientetambémpossuiCPF,RGeidade.Paracolocarmosessasinformaçõesnoclientequecriamosprecisamosdocódigo:
Clientecliente=newCliente("VictorHarada");cliente.Cpf="123.456.789-01";cliente.Rg="21.345.987-x";cliente.Idade=25;
Vejaqueemtodasas linhasestamosrepetindoonomedavariávelqueguardaa referênciaparaocliente.Para evitar essa repetição, podemosutilizaros initializersdoC#.O Initializer éumblocodecódigoqueserveparainicializaraspropriedadespúblicasdoobjeto.
Clientecliente=newCliente("VictorHarada"){//blocodeinicializaçãoCpf="123.456.789-01",Rg="21.345.987-x",Idade=25};
1. Ao modelar um sistema de controle de aviões em um aeroporto, todos os aviões possuem,obrigatoriamente,umcódigoeumaempresa,alémdisso,opcionalmente,umacidadedeentradaesaída.
Qualsoluçãoparecesermaisfácildemanter?
Criar um construtor para código e empresa, e quatro propriedades: código, empresa, cidade deentradaedesaída.
Criarumconstrutorparacódigo,empresa,entradaesaídaenãocriarpropriedades.
Criarquatropropriedades:código,empresa,cidadedeentradaedesaída.
Criarumconstrutorparacódigoeempresa,eduaspropriedadescidadedeentradaedesaída.
2. QualdasopçõesaseguirrepresentaumconstrutordaclasseClientequerecebeonomeeorg?
classCliente{//OutrosatributosdaclasseClientepublicstringNome{get;set;}
8.2PARASABERMAIS—INITIALIZER
8.3EXERCÍCIOS
8.2PARASABERMAIS—INITIALIZER 59
publicstringRg{get;set;}publicCliente(stringnome,stringrg){this.Nome=nome;this.Rg=rg;}//Outrosmétodoseconstrutores}
classCliente{//OutrosatributosdaclasseClientepublicstringNome{get;set;}publicstringRg{get;set;}publicCliente(stringnome){this.Nome=nome;this.Rg=rg;}//Outrosmétodoseconstrutores}
classCliente{//OutrosatributosdaclasseClientepublicstringNome{get;set;}publicstringRg{get;set;}publicvoidCliente(stringnome,stringrg){this.Nome=nome;this.Rg=rg;}//Outrosmétodoseconstrutores}
classCliente{//OutrosatributosdaclasseClientepublicstringNome{get;set;}publicstringRg{get;set;}publicintCliente(stringnome,stringrg){this.Nome=nome;this.Rg=rg;}//Outrosmétodoseconstrutores}
3. Façacomqueonomepossa,opcionalmente,serpassadonaconstruçãodaclasseCliente.
60 8.3EXERCÍCIOS
CAPÍTULO9
Agora que já sabemos os conceitos básicos deOrientação aObjetos, chegou a hora de aprendermoscomoganhar produtividade utilizando oVisual Studio para desenvolver uma interface gráfica para oprojetodobanco.Vamoscriarumnovoprojetoutilizandooatalho"Ctrl+Shift+N"doVisualStudio.Esse atalho abrirá a janela de novo projeto.Nessa janela escolheremos novamente o tipo "WindowsFormApp".Onomedessenovoprojetoserá"Banco".
Dentrodesseprojeto,queremoscolocarcamposdetextoparamostrarasinformaçõesdaconta,paraisso utilizaremos um novo componente do Windows form chamado TextBox . Colocaremos três
TextBoxdentrodoformulário.
INTRODUÇÃOAOVISUALSTUDIOCOMWINDOWSFORM
9INTRODUÇÃOAOVISUALSTUDIOCOMWINDOWSFORM 61
62 9INTRODUÇÃOAOVISUALSTUDIOCOMWINDOWSFORM
Paradefiniro textoqueseráexibidonoTextBox, precisaremosdeumavariável queguardará a
referência para o componenteTextBox. Para definir o nome dessa variável, devemos clicar com o
botãodireitonoTextBoxeescolheraopçãoProperties
OVisualC#colocaráajanelaPropertiesemdestaque:
DentrodaProperties,procureocampo(Name).Onomequeforcolocadonessecamposeráo
nomedavariávelqueconteráareferênciaparaainstânciadeTextBox.Vamos,porexemplo,definir
queonomedocamposerátextoTitular.
PodemosutilizarareferênciaparaoTextBoxparadefinirotextoqueseráexibido:
textoTitular.Text="Textodaminhacaixadatexto";
VamoschamarosoutrosTextBoxdetextoNumeroetextoSaldo.Agoraprecisamosdefiniro
9INTRODUÇÃOAOVISUALSTUDIOCOMWINDOWSFORM 63
códigodoformulárioqueseráutilizadoparapreencherasinformaçõesdoformulário.
Para fazer com que o formulário comece preenchido com a informação do titular da conta,precisamoscriarummétodono formulárioque será responsávelpor sua inicialização.Podemos criaressemétododandoumduplocliquenoformulário:
privatevoidForm1_Load(objectsender,EventArgse){//carregueoscamposdeseuformulárioaqui}
Dentrodessemétodo,queremospreencherasinformaçõesdoformuláriocomosdadosdeumacontaqueseráinstanciada.Vamosinicialmenteinstanciaracontaqueserágerenciadapelaaplicação:
privatevoidForm1_Load(objectsender,EventArgse){Contac=newConta();}
Porém esse código gera um erro de compilação pois nesse projeto ainda não criamos a classeConta.FaremosoVisualStudiogeraradeclaraçãodessaclasse.Coloqueocursordotecladosobreo
nomedaclasseContaeaperteoatalhoCtrl+.,oVisualStudiodaráaopçãoGenerateclass
for'Conta':
Não precisamos nos preocupar em criar cada classe do projeto manualmente, podemos deixar opróprioVisualStudiofazerotrabalho!Mudeavisibilidadedaclassegeradaparapublic.
//ArquivoConta.cspublicclassConta{
}
Agora vamos voltar ao código do formulário e inicializar a propriedade Numero da conta da
9.1INTRODUÇÃOPRÁTICAAOSATALHOSDOVISUALSTUDIO
64 9.1INTRODUÇÃOPRÁTICAAOSATALHOSDOVISUALSTUDIO
variávelc:
privatevoidForm1_Load(objectsender,EventArgse){Contac=newConta();c.Numero=1;}
Ao adicionarmos essa linha, teremos novamente um erro de compilação, pois a conta ainda nãopossuiapropriedadeNumero.ColoqueocursorsobreapropriedadeNumero e aperte novamenteo
Ctrl+..Dessa vez o visual studiomostrará a opçãoGenerate property stub for 'Numero' in'Banco.Conta',escolhaessaopção.
ComissoapropriedadeserácriadaautomaticamentedentrodaclasseConta.
publicclassConta{publicintNumero{get;set;}}
VamostambémdeclararapropriedadeSaldodentrodaConta,para issoutilizaremosumnovo
atalhodovisualstudio.AbaixodapropriedadeNumeroquefoideclaradaanteriormente,digiteprope
depoisaperteateclatabduasvezes:
publicclassConta{publicintNumero{get;set;}
prop+<tab>+<tab>}
Esseéoatalhoparadeclararumanovapropriedadepúblicadentrodocódigo.
publicclassConta{publicintNumero{get;set;}
publicintMyProperty{get;set;}}
9.1INTRODUÇÃOPRÁTICAAOSATALHOSDOVISUALSTUDIO 65
Vejaque,napropriedadecriadapelovisualstudio,otipodapropriedadeeseunomeestãomarcadoscom uma cor de fundo diferente porque ainda não falamos qual será o tipo e o nome da novapropriedade.Comoestamoscriandoapropriedadeparaosaldodaconta,colocaremosotipodouble.
Depoisdedefinirotipodapropriedade,aperteateclatab,issomudaráofocodoeditorparaonome
dapropriedade.DigiteonomeSaldo:
publicclassConta{publicintNumero{get;set;}
publicdoubleSaldo{get;set;}}
MasapenasacontapodealteraroSaldo,asoutrasclassesdevemconseguirfazerapenasaleitura.
Porissomarcaremososetdapropriedadecomapalavraprivate.
publicdoubleSaldo{get;privateset;}
Damesma forma que criamos a propriedade com o atalho prop + <tab> + <tab>, também
podemoscriarumconstrutorparaaclasseutilizandooctor+<tab>+<tab>.
Paraterminaradeclaraçãodaspropriedadesdaconta,vamoscolocaroTitular.Volteàclassedo
formulário principal da aplicação. Dentro do código da inicialização formulário, instancie um novoclientepassandoseunomecomoargumentodoconstrutor:
privatevoidForm1_Load(objectsender,EventArgse){Contac=newConta();c.Numero=1;Clientecliente=newCliente("victor");}
Isso novamente fará o Visual Studio apontar erros de compilação no código e, novamente,utilizaremosoCtrl+. para corrigir esse erro.Coloque o cursor do teclado sobre o tipo cliente,
aperteCtrl+.eselecioneaopçãoGenerateclassfor'Cliente'.Modifiqueavisibilidadeda
classecriadaparapublicevoltenovamenteàclassedoformulário.
OcódigodoformulárioaindapossuioerrodecompilaçãoporqueaclasseClientequeacabamos
decriarnãopossuiumconstrutorquerecebeumastringcomoargumento.Entãovamosnovamente
colocar o cursor do teclado sobre o erro de compilação, apertar Ctrl + . e escolher a opção
Generateconstructorstubin'Banco.Cliente'.
66 9.1INTRODUÇÃOPRÁTICAAOSATALHOSDOVISUALSTUDIO
ComissocriamosautomaticamenteoconstrutordentrodaclasseCliente.
publicclassCliente{privatestringp;
publicCliente(stringp){this.p=p;}}
Vejaquenocódigodoconstrutorovalordoargumentopassadoéguardadodentrodeumatributoque foi declarado automaticamente, porém queremos guardar esse valor dentro de uma propriedadechamadaNomedoCliente.Apagueoatributoquefoicriadoautomaticamentepelovisualstudioe
depoismodifiqueocódigodoconstrutorpara:
publicclassCliente{publicCliente(stringp){this.Nome=p;}}
Quandomodificarmosocódigo,oVisualStudioautomaticamentemostraráumerrodecompilaçãonaclasseClienteporqueapropriedadeNomeaindanãofoideclarada,entãovamoscriá-la.Dentrodo
códigodoconstrutor,coloqueseucursorsobreapalavraNomeedepoisaperteCtrl+.,escolhaa
opçãoGenerate property stub for 'Nome' in 'Banco.Cliente'. Com isso, o Visual Studio
criaráautomaticamenteapropriedadeNomedentrodaclasseCliente:
publicclassCliente{publicCliente(stringp){this.Nome=p;}
publicstringNome{get;set;}}
Agoravoltandoaocódigodoformulário,precisamosguardaroclientequefoicriadonapropriedadeTitulardaConta:
9.1INTRODUÇÃOPRÁTICAAOSATALHOSDOVISUALSTUDIO 67
privatevoidForm1_Load(objectsender,EventArgse){Contac=newConta();c.Numero=1;Clientecliente=newCliente("victor");c.Titular=cliente;}
Comessecódigotemosnovamenteumerrodecompilação,entãoutilizaremosoCtrl+. para
criarapropriedadeTitulardentrodaConta.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Depois de criarmos a classeConta, precisamosmostrar seus dados nosTextBox's que foram
adicionados.Comovimos,paracolocarotextoqueserámostradoemumTextBox,precisamosapenas
escrever na propriedade Text do objeto. Então paramostrarmos o nome do titular, precisamos do
seguintecódigo:
privatevoidForm1_Load(objectsender,EventArgse){Contac=newConta();//inicializaaContac
textoTitular.Text=c.Titular.Nome;}
No caso do número da conta, precisamos convertê-lo para uma string antes de escrevê-lo na
propriedadeText.
Quandoqueremos fazer conversões entre os tipos básicos doC#, utilizamos uma classe chamadaConvertdoC#.Dentrodessaclasse,podemosutilizarométodoToStringparaconverterum tipo
primitivodalinguagemparaumastring.OcódigoparamostraraspropriedadesNumeroeSaldo
dacontaficadaseguinteforma:
EditoraCasadoCódigocomlivrosdeumaformadiferente
9.2ACLASSECONVERT
68 9.2ACLASSECONVERT
textoNumero.Text=Convert.ToString(c.Numero);textoSaldo.Text=Convert.ToString(c.Saldo);
Agora vamos implementar botões no formulário quemanipulam a conta que está sendo exibida.Vamos inicialmente implementar aoperaçãodedepósito.Para isso, arrasteparadentrodo formulárioumanovacaixadetextoefaçacomqueonomedavariáveldessacaixasejatextoValor.Alémdessa
caixa,arrasteumnovobotãoparaoformulário.Quandoousuárioclicarnessebotão,ocódigodevelerovalordigitadonacaixatextoValoreconvertê-loparaumdoublequeserápassadoparaométodo
Deposita.
Dêumduplocliquenobotãoparaassociarumaaçãoemseueventodeclique.Dentrodaaçãodobotão,parapegarmosotextoquefoidigitadonotextoValor,precisamosapenaslerasuapropriedade
Text:
privatevoidbutton1_Click(objectsender,EventArgse){stringvalorDigitado=textoValor.Text;}
AgoraprecisamosfazeraconversãodovalorDigitadoparaotipodoubledoC#.Pararealizar
essaconversão,utilizaremosométodoToDoubledaclasseConvert:
privatevoidbutton1_Click(objectsender,EventArgse){stringvalorDigitado=textoValor.Text;doublevalorOperacao=Convert.ToDouble(valorDigitado);}
E agora que temos o valor da operação no tipo correto, vamos utilizar ométodoDeposita da
classeConta:
privatevoidbutton1_Click(objectsender,EventArgse){stringvalorDigitado=textoValor.Text;doublevalorOperacao=Convert.ToDouble(valorDigitado);c.Deposita(valorOperacao);}
Mas a ação desse botão não pode acessar uma variável que foi declarada dentro do métodoForm1_Load. Para que amesma conta possa ser utilizada emdiferentesmétodosdo formulário, ela
precisaserdeclaradacomoumatributodaclassedoformulárioquefoigeradapeloVisualStudio:
publicclassForm1:Form{privateContac;
//restodaclassedoformulário.}
9.3OPERAÇÕESNACONTA:SAQUEEDEPÓSITO
9.3OPERAÇÕESNACONTA:SAQUEEDEPÓSITO 69
DentrodoForm1_Load,guardaremosacontacriadadentrodonovoatributodoformulário:
privatevoidForm1_Load(objectsender,EventArgse){//Criaumanovacontaeguardasuareferêncianoatributodoformuláriothis.c=newConta();
//inicializaemostraacontanoformulário}
Comoacontaéumatributodoformulário,podemosacessá-laapartirdométodobutton1_Click.
Masainda temosumerrodecompilaçãoporqueométodoDeposita não existe na classeConta.
Entãovamoscriá-loutilizandooVisualStudio.Dentrodométodobutton1_Click,coloqueocursor
dotecladosobreométodoDepositaeaperteCtrl+.,edepoisescolhaaopçãoGenerateMethod
stubfor'Deposita'in'Banco.Conta'.
Comisso,oVisualStudioautomaticamentecolocaráométododentrodaclasseConta.
internalvoidDeposita(doublep){thrownewNotImplementedException();}
Apagueaimplementaçãopadrãodessemétodo,mudesuavisibilidadeparapublice,porfim,faça
asuaimplementaçãoparaalógicadedepósito.Ocódigodeveficarparecidocomoquesegue:
publicvoidDeposita(doublevalorOperacao){this.Saldo+=valorOperacao;}
Para terminar a lógica de depósito, precisamos apenas atualizar o valor do saldo na interface dousuário. Abra novamente a ação do botão de depósito dentro do código do formulário principal daaplicação(métodobutton1_ClickdaclasseForm1).Dentrodessemétodo,vamosatualizarotexto
mostradonocampotextoSaldocomovalordosaldodaconta:
privatevoidbutton1_Click(objectsender,EventArgse){stringvalorDigitado=textoValor.Text;doublevalorOperacao=Convert.ToDouble(valorDigitado);this.c.Deposita(valorOperacao);textoSaldo.Text=Convert.ToString(this.c.Saldo);}
70 9.3OPERAÇÕESNACONTA:SAQUEEDEPÓSITO
Para finalizarmos essa ação, podemos avisar o usuário que a operação foi realizada com sucessoutilizandoummessagebox.Colocaremosacaixademensagemutilizandooatalhombox+<tab>+
<tab>,esseatalhodeclaraocódigodoMessageBox.Show:
privatevoidbutton1_Click(objectsender,EventArgse){stringvalorDigitado=textoValor.Text;doublevalorOperacao=Convert.ToDouble(valorDigitado);this.c.Deposita(valorOperacao);textoSaldo.Text=Convert.ToString(this.c.Saldo);MessageBox.Show("Sucesso");}
Comovimos,aaçãodeumbotãodoformulárioéummétododeclaradonaclassedoformulárioquecontém o botão. Vimos também que o Visual Studio gera o nome dos métodos na formabutton<numero>_Click.Esseéumnomequepodefacilmentecausarconfusãoegerarproblemasde
manutençãodocódigo.
EssenomegeradopeloVisualStudionaverdadeébaseadonapropriedade(Name)docomponente
Button. Então, para que o Visual Studio gere nomes mais amigáveis para os botões, podemos
simplesmentemudaro(Name)dobotãonajanelaProperties.
Vamos colocar umnovobotão no formulário que implementará a operação de saque.Arraste umnovobotãoparaoformulárioecomo(Name)dessebotãoutilizebotaoSaque.Agoradêumduplo
cliquenonovobotãoparagerarocódigodesuaaçãodeclique.IssocriaráumnovométodochamadobotaoSaque_Click:
privatevoidbotaoSaque_Click(objectsender,EventArgse){stringvalorDigitado=textoValor.Text;doublevalorOperacao=Convert.ToDouble(valorDigitado);this.c.Saca(valorOperacao);textoSaldo.Text=Convert.ToString(this.c.Saldo);MessageBox.Show("Sucesso");}
RestaapenasimplementarmosométodoSacadaConta:
publicvoidSaca(doublevalor){this.Saldo-=valor;}
Mude também o (Name) do botão de depósito para botaoDeposito . Na próxima seção
aprenderemoscomorenomearonomedaaçãodobotãosemcausarproblemasdecompilação.
9.4CONTROLANDOONOMEDAAÇÃODEUMBOTÃO
9.4CONTROLANDOONOMEDAAÇÃODEUMBOTÃO 71
TEXTODOBOTÃO
O texto de um botão do Windows Form também pode ser customizado através de suapropriedadeText.EssapropriedadepodesermodificadanajanelapropertiesdoVisualStudio.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
VamosolharocódigodoconstrutordoClientequeimplementamosanteriormente:
publicclassCliente{publicCliente(stringp){this.Nome=p;}}
Veja que nesse código estamos recebendo um parâmetro chamado p, mas o que esse nome p
significa?Quando criamos uma variável, é sempre importante utilizarmos nomes que descrevem suafunçãodentrodocódigo,senãopodemosacabardificultandoasualeituraecompreensãofuturas.
Masrenomearumavariávelexistenteéuma tarefaárdua,poisnãoadiantaapenas renomearmosadeclaraçãodavariável,precisamos tambémmudar todosos lugaresqueautilizam.Quandoqueremosfazeruma renomeaçãodevariáveis, podemosutilizaroprópriovisual studiopara fazer esse trabalhoatravésdoatalhoCtrl+R,Ctrl+R(Ctrl+Rduasvezes).
VamosutilizaressenovoatalhopararenomearoparâmetroprecebidonoconstrutordoCliente.
JáconheceoscursosonlineAlura?
9.5 RENOMEANDO VARIÁVEIS, MÉTODOS E CLASSES COM OVISUALSTUDIO
72 9.5RENOMEANDOVARIÁVEIS,MÉTODOSECLASSESCOMOVISUALSTUDIO
Paraisso,coloqueocursordotecladosobreadeclaraçãodoparâmetropousobreumdeseususose
depoisaperteCtrl+R,Ctrl+R.Issoabriráumanovajanelaondepodemosdigitarqualéonovo
nomeque queremos utilizar para essa variável.Digitenome na caixa de texto e depois confirme a
mudança.ComissooVisualStudiofaráorenameautomáticodavariáveldentrodocódigo.Omesmoatalhopodeserusadopararenomearmosclasses,métodos,atributosepropriedadesdocódigo.
AgorautilizaremosesseatalhoderenameparamodificaronomedaaçãodobotãodedepósitoparabotaoDeposito_Click.Coloqueocursordo tecladosobreonomedométodobutton1_Click da
classeForm1EaperteCtrl+R,Ctrl+RerenomeieométodoparabotaoDeposito_Click.
Podemostambémrenomearargumentodemétodosutilizandoesseatalho.AbraométodoSacada
classeContaecoloqueocursordotecladosobreavariávelvalorOperacaoedepoisaperteoCtrl
+R,Ctrl+R,mudeonomedavariávelparavalor.FaçaomesmocomométodoDeposita.
Noformulárioprincipal,acontaprincipaldaaplicaçãoestáutilizandoccomonomedevariável,
porémcnãoéumbomnome,poiselenãoéumnomedescritivo.Tenteutilizaressenovoatalhoque
aprendemosparamudaronomedesseatributoparaconta,vejaqueoVisualStudiorenomearátantoa
declaraçãodoatributoquantoseususos.
Nestecapítuloconseguimosmostrarasinformaçõesdacontaatravésdainterfacedaaplicação,comissoousuárioconseguesaberoqueestáacontecendocomsuaconta,porémumacaracterísticamuitoimportantedeprogramascominterfacegráficaéaorganizaçãodasinformações.
Noformulárioquecriamos,comoousuáriosabequaissãooscamposquerepresentamosaldo,onúmero e o titular da conta?Precisamos de alguma forma para indicar qual é a informação que estáarmazenadadentrodeumTextBox,para issoutilizaremosumnovocomponentedoWindowsForm
chamadoLabel.Olabel funciona como uma etiqueta para nossos campos de texto.Através da
propriedadeTextdaLabel,quepodesermodificadapelajanelaproperties,podemosdefinirqual
éotextoqueseráexibido.Vejacomoficaaaplicaçãoquandoutilizamosolabel:
9.6 PARA SABER MAIS — ORGANIZANDO O FORMULÁRIO COMLABELEGROUPBOX
9.6PARASABERMAIS—ORGANIZANDOOFORMULÁRIOCOMLABELEGROUPBOX 73
Mas e quando temos uma interface gráfica muito complexa? Nesses casos, podemos ter muitasfuncionalidadesouinformaçõesdentrodeumaúnicateladaaplicação.Paraessasituação,éumapráticacomum criar grupos de elementos com funcionalidades semelhantes. Para organizar os grupos decomponentes de um formulário, no Windows Form possuímos mais um componente chamadoGroupBox
UtilizandooGroupBox,podemosagrupardiversoscomponentesdiferentessobumúnicotítulo.O
formuláriodonossoprojeto,porexemplo,ficariadaseguinteforma:
74 9.6PARASABERMAIS—ORGANIZANDOOFORMULÁRIOCOMLABELEGROUPBOX
ParafacilitaraconsultadosatalhosdoVisualStudio,nessaseçãovamoslistarosatalhosvistosnocapítulo:
Ctrl+Shift+N:criaumnovoprojetodentrodoVisualStudio;
Ctrl+.:utilizadoparafazerconsertosrápidosnocódigo.Quandoestamosutilizandoumaclassequenãoexiste,eledeclaraaclassedentrodoprojeto.Aoutilizarmosumapropriedadeoumétodoinexistente,oatalhocriaautomaticamenteocódigoparaapropriedadeoumétodo;
Ctrl+R,Ctrl+R:renomeiaclasses,métodos,propriedades,atributosouvariáveisutilizadasnocódigo;
Ctrl+:autocomplete;
ctor++:declaraumconstrutordentrodaclasse;
prop++:declaraumapropriedadedentrodaclasse;
mbox++:declaraocódigodoMessageBox.Show().
9.7RESUMODOSATALHOSDOVISUALSTUDIO
9.7RESUMODOSATALHOSDOVISUALSTUDIO 75
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
1. Monteumformulárioquemostreoscampostitular,saldoenumerodeumaConta.Façacomqueavariável queguardao campo titular seja chamadadetextoTitular, a que guarda o saldo seja
textoSaldoeaqueguardaonumerosejatextoNumero.
Noloaddoformulário,escrevaumcódigoquecriaumacontacomtitularVictorenumero1.MostreosdadosdessacontanoscampostextoTitular,textoSaldoetextoNumerodoformulário.
2. Crieumnovocampode textono formuláriochamadotextoValor.Adicione tambémumnovo
botão que quando clicado executará a lógica de depósito utilizando o valor digitado no campocriado.Depoisdeexecutaralógica,atualizeosaldoatualqueéexibidopeloformulário.
3. Coloqueumnovobotãonoformulário.FaçacomqueaaçãodocliquedessebotãoexecuteumsaquenacontausandoovalordocampotextoValor.Apóso saque, atualize as informaçõesque são
exibidasparaousuário.
Umclienteprecisasermaiordeidadeouemancipadoparaabrirumacontanobanco.Alémdisso,ele tambémprecisa de umCPF. Para verificar isso, o sistema possui ummétodo que verifica se umclientepodeounãoabrirumaconta:
publicboolPodeAbrirContaSozinho{get{return(this.idade>=18||this.documentos.contains("emancipacao"))&&!string.IsNullOrEmpty(this.cpf);}}
VocêpodetambémfazerocursodatadessaapostilanaCaelum
9.8EXERCÍCIOS
9.9PARASABERMAIS—TIPOSIMPLÍCITOSEAPALAVRAVAR
76 9.8EXERCÍCIOS
Percebaquepodemoscriartrêsvariáveisparaquenossoifnãofiquemuitocomplexo:
publicboolPodeAbrirContaSozinho{get{boolmaiorDeIdade=this.idade>=18;boolemancipado=this.documentos.contains("emancipacao");boolpossuiCPF=!string.IsNullOrEmpty(this.cpf);return(maiorDeIdade||emancipado)&&possuiCPF;}}
Desse jeito,ocódigo ficamais limpoe fácildeentender.Porém, tivemosque ficardeclarandoostiposdasvariáveiscomobool.NãoseriaóbvioparaoC#queessasvariáveissãodotipobool.Sim!
Eeleéespertoosuficienteparainferirisso:
publicboolPodeAbrirContaSozinho{get{varmaiorDeIdade=this.idade>=18;varemancipado=this.documentos.contains("emancipacao");varpossuiCPF=!string.IsNullOrEmpty(this.cpf);return(maiorDeIdade||emancipado)&&possuiCPF;}}
Variáveisdentrodemétodospodemserdeclaradascomovar emC#queo seu tipo é inferidoautomaticamente.Paraocompiladoracertarqualotipodavariáveleladeveserinicializadanomesmoinstantequeédeclaradaenãopodeseratribuídoovalornull.
publicboolPodeAbrirContaSozinho{get{varmaiorDeIdade;//estalinhanãocompilamaiorDeIdade=this.idade>=18;//...}}
Porfim,umavariáveldeclaradacomovarpossuiumtipobemdefinidoenãopodeseralterado.A
tipageméinferida,masotipodavariávelnãopodeseralteradaàmedidaqueocódigoéexecutado,oquefazcomqueocódigoseguintenãofaçasentidoenãocompile:
varguilherme=newCliente();guilherme=newConta();
1. Observeocódigoaseguireassinaleaalternativacorreta.
varconta=newConta();conta.Titular=newCliente();
9.10EXERCÍCIOSOPCIONAIS
9.10EXERCÍCIOSOPCIONAIS 77
Nãocompilapoisavariávelédeumtipodinâmico.
Compilaefazcomqueavariávelcontapossareferenciarqualquertipodeobjeto.
Nãocompilapoiselenãotemcomoadivinharsevaréumacontanovaoujáexistente.
CompilaefazcomqueavariávelcontasejadotipoConta.
2. Oqueaconteceaotentarcompilarerodarocódigoaseguir?
varsimples=newConta();//linha1simples=newConta();//linha2simples=newCliente();//linha3
Alinha2nãocompilapoisnãopodemosreatribuirumavariável.
Alinha3nãocompilapoisotipodeumavariávelnãopodesertrocadoeeleéinferidoaodeclararavariável.
Compilaenofimdas3linhasdecódigoavariávelsimplesapontaráparaumCliente.
Alinha1nãocompiladevidoaocódigodalinha2e3.
3. Oqueaconteceaocompilarerodarocódigoaseguir?
varconta;conta=newConta();conta.Deposita(300);
Nãocompilapoiscontanãoteveumvaloratribuídojánaprimeiralinha.
Compilamasnãoroda,dandoerrodeexecuçãonalinha2poistentamosacessarumavariávelsemvalor.
Compilaeroda.
4. Oqueaconteceaocompilareexecutarocódigoadiante?
vartamanho=5;tamanho=tamanho/2.0;MessageBox.Show(tamanho);
Ocódigonãocompilanalinha2.
Ocódigocompilaerodaimprimindo2.
Ocódigocompilamasnãorodapois5nãoédivisívelpor2.0.
Ocódigocompilaeroda,imprimindotamanho=2.5
78 9.10EXERCÍCIOSOPCIONAIS
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
9.10EXERCÍCIOSOPCIONAIS 79
CAPÍTULO10
Imagineagoraquenossobancorealizedepósitosesaquesdeacordocomotipodaconta.Seacontaforpoupança,oclientedevepagar0.10porsaque.Seacontaforcorrente,nãohátaxa.
Paraimplementaressaregradenegócio,vamoscolocarumifnométodoSaca:
publicvoidSaca(doublevalor){if(this.Tipo==???????????){this.Saldo-=valor+0.10;}else{this.Saldo-=valor;}}
PodemoscriarumatributonaConta,queespecificaotipodacontacomo,porexemplo,uminteiro
qualquerondeonúmero1representaria"contapoupança"e2"contacorrente".
Aimplementaçãoseriaalgocomo:
publicclassConta{publicintNumero{get;set;}publicdoubleSaldo{get;privateset;}
publicClienteTitular{get;set;}
publicintTipo{get;set;}
publicvoidSaca(doublevalor){if(this.Tipo==1){this.Saldo-=valor+0.10;}else{this.Saldo-=valor;}}
publicvoidDeposita(doublevalor){this.Saldo+=valor;}}
HERANÇA
80 10HERANÇA
Vejaqueuma simples regra denegócio comoessa fez nosso código crescermuito.Epoderia serpior:imaginesenossobancotivesse10tiposdecontasdiferentes.Esseifseriamaiorainda.
Precisamosencontrarumamaneiradefazercomqueacriaçãodenovostiposdecontanãoimpliqueemumaumentodecomplexidade.
UmasoluçãoseriaterclassesseparadasparaConta(queéacorrente)eContaPoupanca:
publicclassConta{publicintNumero{get;set;}publicdoubleSaldo{get;privateset;}
publicClienteTitular{get;set;}
publicvoidSaca(doublevalor){this.Saldo-=valor;}
publicvoidDeposita(doublevalor){this.Saldo+=valor;}}
publicclassContaPoupanca{publicintNumero{get;set;}publicdoubleSaldo{get;privateset;}
publicClienteTitular{get;set;}
publicvoidSaca(doublevalor){this.Saldo-=(valor+0.10);}
publicvoidDeposita(doublevalor){this.Saldo+=valor;}}
Ambasasclassespossuemcódigobemsimples,masagoraoproblemaéoutro:arepetiçãodecódigoentreambasasclasses.Seamanhãprecisarmosguardar"CPF",porexemplo,precisaremosmexeremtodasasclassesquerepresentamumacontanosistema.Issopodesertrabalhoso.
Aideiaé,portanto,reaproveitarcódigo.Vejaque,nofim,umaContaPoupancaéumaConta,pois
ambostemNumero,SaldoeTitular.Aúnicadiferençaéocomportamentonomomentodosaque.
PodemosfalarqueumaContaPoupancaéumaConta:
publicclassContaPoupanca:Conta
10.1REAPROVEITANDOCÓDIGOCOMAHERANÇA
10.1REAPROVEITANDOCÓDIGOCOMAHERANÇA 81
{
}
Quandoumaclasseédefinidacomo:,dizemosqueelaherdadaoutra(Conta)eporissoelaganhatodososatributosemétodosdaoutraclasse.Porexemplo,seContaPoupancaherdardeConta,isso
querdizerqueelateráNumero,Saldo,Titular,Saca()eDeposita()automaticamente,sem
precisarfazernada.DizemosqueaclasseContaPoupancaéumasubclasseouclassefilha da classeContaequeContaéumaclassebaseouclassepaidaContaPoupanca.Vejaocódigoaseguir:
//ArquivoContaPoupanca.cspublicclassContaPoupanca:Conta{
}
//CódigonoformulárioqueutilizaaContaPoupancaContaPoupancac=newContaPoupanca();c.Deposita(100.0);
Bastausaranotação:eoC#automaticamenteherdaosmétodoseatributosdaclassepai.Masa
ContaPoupanca tem o comportamento de Saca() diferente. Para isso, basta reescrever o
comportamentonaclassefilha,usandoapalavraoverrideemudandoaclassepaiparaindicarqueo
métodopodesersobrescrito(virtual):
//ArquivoConta.cspublicclassConta{publicvirtualvoidSaca(doublevalor){this.Saldo-=valor;}
//Restodocódigodaclasse}
//ArquivoContaPoupanca.cspublicclassContaPoupanca:Conta{publicoverridevoidSaca(doublevalor){this.Saldo-=(valor+0.10);}}
//CódigodoformuláriodaaplicaçãoContaPoupancac=newContaPoupanca();
//chamaocomportamentoescritonopai//OSaldoterminaem100.0depoisdessalinhac.Deposita(100.0);
//chamaocomportamentoescritonaContaPoupanca//OSaldoterminacomovalor49.90c.Saca(50);
82 10.1REAPROVEITANDOCÓDIGOCOMAHERANÇA
VejanessecódigoqueinvocamostantoDeposita()quantoSaca().Nodepósito,comoaclasse
filhanãoredefiniuocomportamento,ométodoescritonaclassepaiseráutilizado.
Jánosaque,ocomportamentousadoéoquefoisobrescritonaclassefilha.
Mas o código anterior ainda não compila. Repare que o método Saca() da ContaPoupanca
manipulaoSaldo.MasSaldo é privado!Atributos privados só sãovisíveis para a classe queos
declarou.Osfilhosnãoenxergam.
Queremos proteger nosso atributo mas não deixá-lo privado nem público. Queremos proteger osuficienteparaninguémdeforaacessar,masapenasquemherdateracesso.Pararesolver,alteraremosomodificador de acesso para protected. Atributos/métodos marcados como protected são visíveisapenasparaaprópriaclasseeparaasclassesfilhas:
publicclassConta{publicintNumero{get;set;}publicdoubleSaldo{get;protectedset;}
//...}
AclasseContaaindapodeserinstanciadasemproblemas:
Contac=newConta();c.Deposita(100.0);
Vejaquecomherançaconseguimossimplificarereutilizarcódigoaomesmotempo.Aherançaéummecanismopoderosomasdeveserutilizadocomcuidado.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
ObserveasimplementaçõesdosmétodosSacadasclassesContaeContaPoupanca:
Agoraéamelhorhoradeaprenderalgonovo
10.2REAPROVEITANDOAIMPLEMENTAÇÃODACLASSEBASE
10.2REAPROVEITANDOAIMPLEMENTAÇÃODACLASSEBASE 83
publicclassConta{//outrosatributosemétodospublicdoubleSaldo{get;protectedset;}
publicvirtualvoidSaca(doublevalor){this.Saldo-=valor;}}
publicclassContaPoupanca:Conta{publicoverridevoidSaca(doublevalor){this.Saldo-=(valor+0.10);}}
Asimplementaçõesdosdoismétodossãopraticamenteiguais,aúnicadiferençaéquenoSacada
ContaPoupanca colocamos this.Saldo -= (valor + 0.10); ao invés de this.Saldo -=
valor;.
Quando fazemos a sobrescrita de métodos em uma classe filha, muitas vezes, queremos apenasmudarlevementeocomportamentodaclassebase.Nessassituações,nocódigodaclassefilha,podemosreutilizar o código da classe pai com a palavra base chamando o comportamento que queremosreaproveitar.EntãoocódigodoSacadaContaPoupancapoderiaserreescritodaseguinteforma:
publicclassContaPoupanca:Conta{publicoverridevoidSaca(doublevalor){base.Saca(valor+0.10);}}
Comessaimplementação,oSacadaContaPoupancachamaométododaclassebasepassando
como argumento valor + 0.10. Repare também que, como a classe filha não está utilizando a
propriedadeSaldodaConta,elapoderiavoltaraserprivate:
publicclassConta{publicdoubleSaldo{get;privateset;}
//outraspropriedadesemétodos}
Nossobancotemrelatóriosinternosparasabercomoestáasaúdefinanceiradainstituição,alémderelatórios sobreosclientesecontas.Emumdeles, énecessáriocalculara somadosaldode todasascontas(correntes,poupanças,entreoutras)queexistemnobanco.Começandocom"zeroreais":
10.3POLIMORFISMO
84 10.3POLIMORFISMO
publicclassTotalizadorDeContas{publicdoubleValorTotal{get;privateset;}}
PermitimosadicionarContaaonossorelatórioeacumularseusaldo:
publicclassTotalizadorDeContas{publicdoubleValorTotal{get;privateset;}
publicvoidSoma(Contaconta){ValorTotal+=conta.Saldo;}}
Contac1=newConta();Contac2=newConta();
TotalizadorDeContast=newTotalizadorDeContas();t.Soma(c1);t.Soma(c2);
Ótimo.Masoproblemaéquetemosclassesquerepresentamdiferentestiposdecontas,equeremosacumularosaldodelastambém.UmaprimeirasoluçãoseriaterummétodoSoma()paracadaclasse
específica:
publicclassTotalizadorDeContas{publicdoubleValorTotal{get;privateset;}
publicvoidSoma(Contaconta){/*...*/}publicvoidSoma(ContaPoupancaconta){/*...*/}publicvoidSoma(ContaEstudanteconta){/*...*/}//maisummontedemétodosaqui!}
Novamentecaímosnoproblemadarepetiçãodecódigo.
VejaqueContaPoupancaéumaConta.Issoéinclusiveexpressoatravésdarelaçãodeherança
entre as classes. E, já que ContaPoupanca é uma Conta , o C# permite que você passe
ContaPoupancaemlugaresqueaceitamreferênciasdotipoConta!Linguagensorientadasaobjetos,
comoC#,possuemessasoluçãoelegantepraisso.
Vejaocódigoaseguir:
publicclassTotalizadorDeContas{publicdoubleValorTotal{get;privateset;}
publicvoidSoma(Contaconta){ValorTotal+=conta.Saldo;}}
10.3POLIMORFISMO 85
Contac1=newConta();ContaPoupancac2=newContaPoupanca();
TotalizadorDeContast=newTotalizadorDeContas();t.Soma(c1);t.Soma(c2);//funciona!
Ocódigofunciona!Podemospassarc2aliparaométodoSoma().
Mascomoissofunciona?OC#sabequeContaPoupancaherda todososatributosemétodosde
Conta, e portanto, tem a certeza de que existe o atributoSaldo, e que ele poderá invocá-lo sem
maioresproblemas!
Agora,umaContaPoupancatemumnovocomportamento,quepermitecalcularseusrendimentos.
ParaissoodesenvolvedorcriouumcomportamentochamadoCalculaRendimento():
classContaPoupanca:Conta{publicvoidCalculaRendimento(){//...}}
VejaométodoSoma().EleinvocatambémoCalculaRendimento():
publicclassTotalizadorDeContas{publicdoubleValorTotal{get;privateset;}
publicvoidSoma(Contaconta){ValorTotal+=conta.Saldo;conta.CalculaRendimento();//nãocompila!}}
O código anterior não compila. Por quê? Porque o C# não consegue garantir que o que virá navariável conta será uma ContaPoupanca. Naquela "porta" entra Conta ou qualquer filho de
Conta.Portanto,tudooqueoC#conseguegarantiréqueoobjetoqueentraralitemtudoqueConta
tem.Porisso,sópodemosusarmétodoseatributosdefinidospelotipodavariável(nocaso,Conta.)
Essa ideiadeumavariavelconseguir referenciarseupróprio tipooufilhosdesse tipoéconhecidopor polimorfismo. Veja que, com o uso de polimorfismo, garantimos que a classeTotalizadorDeContasfuncionaráparatodonovotipodeContaqueaparecer.
Seno futuroumnovo tipode conta, comoconta investimento, for criada, bastaque elaherdedeContaenãoprecisaremosnuncamodificaressaclasse!Elafuncionaránaturalmente!
Umprogramadorqueconhecebemorientaçãoaobjetosfazusoconstantedepolimorfismo.Veremosmais pra frente como continuar usando polimorfismo para escrever código de qualidade, tomando
86 10.3POLIMORFISMO
cuidadoparanãoabusardessaideia.
1. Qualadiferençaentreprivateeprotected?
Nenhuma.Emambos,oatributo/métodoévisívelparatodos.
Só a própria classe enxerga atributos/métodos private enquanto protected é visto pela
própriaclassemaisasclassesfilhas.
Só a própria classe enxerga atributos/métodos protected enquanto private é visto pela
própriaclassemaisasclassesfilhas.
2. Paraqueserveapalavraoverride?
Paraindicarqueométodoestásobrescrevendoummétododaclassepai.
Paranãopermitiracessoaoatributoporoutrasclasses.
Paraindicarqueessemétodonãodeveserutilizado.
3. Praqueserveapalavravirtual?
Parapermitirqueométodosejasobrescrito.
Paraindicarqueessemétodonãodevesersobrescrito.
Parasobrescreverummétododaclassepai.
Paranãopermitiracessoaoatributoporoutrasclasses.
4. AdicioneaclasseContaPoupancanaaplicação.EssaclassedeveherdardaContaesobrescrever
ocomportamentodométodoSacaparaquetodosossaquesrealizadosnacontapoupançapaguem
umataxadeR$0.10.
Nãoseesqueçadeutilizaraspalavrasvirtualeoverrideparasobrescreverosmétodos.
5. Oqueaconteceaoexecutarmosocódigoaseguir:
Contac1=newContaPoupanca();c1.Deposita(100.0);c1.Saca(50.0);MessageBox.Show("contapoupança="+c1.Saldo);
Contac2=newConta();c2.Deposita(100.0);c2.Saca(50.0);MessageBox.Show("conta="+c2.Saldo);
10.4EXERCÍCIOS
10.4EXERCÍCIOS 87
contapoupanca=49.9econta=49.9
contapoupança=49.9econta=50.0
contapoupança=50.0econta=50.0
contapoupança=50.0econta=49.9
6. FaçacomqueométodoForm1_Load,instancieumaContaPoupancaaoinvésdaConta:
publicpartialclassForm1:Form{//EssaéamesmadeclaraçãoquecolocamosnocapítuloanteriorprivateContaconta;privatevoidForm1_Load(objectsender,EventArgse){this.conta=newContaPoupanca();//restodocódigocontinuaigual}
//códigodorestodoformuláriotambémcontinuaigual}
Reparequenãoprecisamosmodificarotipodavariávelconta,poiscomoaContaPoupancaherda
deConta,podemosutilizaropolimorfismoparaatribuirumareferênciadotipoContaPoupanca
emumavariáveldotipoConta.
Depois demodificar o programa, execute-o e teste a operação de depósito.Repare que na classeContaPoupancanãodeclaramosométodoDeposita,masmesmoassimconseguimosinvocá-lo
dentrodocódigo,issoépossívelpoisquandoutilizamosherança,todoocomportamentodaclassepaiéherdadopelaclassefilha.
Testetambémobotãodesaque.ComoaContaPoupancasobrescreveométodoSacadaConta,
ao apertarmos o botão de saque, estamos invocando o comportamento especializado que foiimplementadonaContaPoupancaaoinvésdeusaroquefoiherdadodaConta.
7. CrieaclasseContaCorrentedentrodoprojetoefaçacomqueelaherdedaclasseConta.
TodasasoperaçõesnaContaCorrenteserãotarifadas,emtodoSaque,precisamospagarumataxa
deR$0.05eparaosdepósitos,R$0.10,ouseja,naContaCorrente, precisaremos sobrescrever
tantoométodoSacaquantooDeposita.Nãoseesqueçadeusarovirtualeoverridepara
fazerasobrescritanocódigo.
Depois de criar a ContaCorrente, modifique novamente o formulário para que ele mostre as
informaçõesdeumaContaCorrenteaoinvésdeumaContaPoupanca.
8. (Opcional) Implemente a classe TotalizadorDeContas com uma propriedade chamada
SaldoTotaleummétodochamadoAdicionaquedevereceberumacontaesomarseusaldoao
88 10.4EXERCÍCIOS
saldototaldototalizador.Escrevaumcódigoquetestaototalizador.
PodemospassarumainstânciadeContaCorrenteparaoAdicionadototalizador?Porquê?
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Nestecapítulo,vimosquequandofazemosaclasseContaPoupancaherdardaclasseConta,ela
recebeautomaticamentetodososatributos,propriedadesemétodosdaclassepai,porémosconstrutoresdaclassepainãosãoherdados.Entãoseaclassefilhaprecisadeumconstrutorqueestánaclassepai,eladeveexplicitamentedeclararesseconstrutoremseucódigo.
Imagineporexemplo,queparaconstruirmosacontaprecisamospassaropcionalmenteseunúmero:
publicclassConta{publicintNumero{get;set;}//ConstrutorsemargumentospublicConta(){}
publicConta(intnumero){this.Numero=numero;}}
Agora na classe ContaPoupanca queremos passar o número na construção do objeto, como o
construtornãoéherdado,precisamoscolocaradeclaraçãoexplicitamente:
publicclassContaPoupanca:Conta{publicContaPoupanca(intnumero){//ApropriedadeNumeroveioherdadadaclasseContathis.Numero=numero;}
EditoraCasadoCódigocomlivrosdeumaformadiferente
10.5PARASABERMAIS—OQUEÉHERDADO?
10.5PARASABERMAIS—OQUEÉHERDADO? 89
}
Nesse construtor que acabamos de declarar na classe ContaPoupanca , fizemos apenas a
inicializaçãodapropriedadenúmero,exatamenteomesmocódigoquetemosnoconstrutordaclassepai,entãoaoinvésderepetirmosocódigo,podemossimplesmentechamaroconstrutorquefoideclaradonaclasseContaapartirdoconstrutordaclasseContaPoupancautilizandoapalavrabase:
publicclassContaPoupanca:Conta{//Estamoschamandooconstrutordaclassepaiquejáfazainicialização//donúmeroeporissoocorpodoconstrutorpodeficarvazio.publicContaPoupanca(intnumero):base(numero){}}
Naverdade,dentrodoC#,semprequeconstruímosumainstânciadeContaPoupanca,oC#sempre
precisachamarumconstrutordaclasseContaparafazera inicializaçãodaclassebase.Quandonão
invocamosexplicitamenteoconstrutordaclassepai,oC#colocaimplicitamenteumachamadaparaoconstrutorsemargumentosdaclassepai:
publicclassContaPoupanca:Conta{//nessecódigooc#chamaráoconstrutorsemargumentosdaclasseConta.publicContaPoupanca(intnumero){this.Numero=numero;}}
SeaclasseContanãodefiniroconstrutorsemargumentos,temosumerrodecompilaçãosenão
invocarmosexplicitamenteumconstrutordaclassepai.
90 10.5PARASABERMAIS—OQUEÉHERDADO?
CAPÍTULO11
Queremos guardar uma lista de contas de nosso banco para poder trabalhar com elas.Uma primeiraalternativa seria criar um conjunto de variáveis, no qual cada variável aponta para uma Conta
diferente:
Contac1=newConta();Contac2=newContaPoupanca();Contac3=newConta();//...
Mas,esequisermosimprimirosaldodetodaselas?PrecisaremosescreverNlinhas,umaparacadaConta:
MessageBox.Show(c1.Titular.Nome);MessageBox.Show(c2.Titular.Nome);MessageBox.Show(c3.Titular.Nome);
Muitotrabalho!CriarumanovaContaseriaumcaos!
Quando queremos guardar diversos objetos, podemos fazer uso de Arrays. Um array é umaestruturadedadosqueconsegueguardarvárioselementoseaindanospossibilitapegaresseselementosdemaneirafácil!
Criarumarrayémuitoparecidocominstanciarumaclasse.Paracriarmos5posiçõesdenúmerosinteiros:
int[]numeros=newint[5];
Acabamosdedeclararumarraydeinteiros,com5posições.Repareanotação[5].Paraguardar
elementosnessasposições,fazemos:
numeros[0]=1;numeros[1]=600;numeros[2]=257;numeros[3]=12;numeros[4]=42;MessageBox.Show("número="+numeros[1]);
Vejaqueaprimeiraposiçãodeumarrayé0(zero).Logo,asposiçõesdeumarrayvãode0(zero)
até(tamanho-1).
VamosagoracriarumarraydeContas:
TRABALHANDOCOMARRAYS
11TRABALHANDOCOMARRAYS 91
Conta[]contas=newConta[5];contas[0]=newConta();
A sintaxe é a mesma. Os elementos guardados pelo array são iguais aos de uma variávelconvencional,quevocêjáestáacostumado.Issoquerdizerquetemospolimorfismotambém!Ouseja,podemosguardar,emumarraydeConta,qualquerfilhodela:
contas[1]=newContaPoupanca();
Sequisermos imprimir todasasContasarmazenadas,podemos fazerum loopnessearray.O loopcomeçaráem0evaiatéotamanhodoarray(contas.Length):
for(inti=0;i<contas.Length;i++){MessageBox.Show("saldo="+contas[i].Saldo);}
PodemosaindausarumaoutrasintaxedoC#,afinalqueremosirparacadaContacemcontas:
foreach(Contacincontas){MessageBox.Show("saldo="+c.Saldo);}
OC#pegacadaelementodoarrayecolocaautomaticamentenavariávelc,imprimindooresultado
quequeremos.
Emmuitassituações,estamosinteressadosemcriarelogoemseguidainicializaroconteúdodeumarray,paraisso,comovimosnessecapítulo,precisaríamosdeumcódigoparecidocomoquesegue:
int[]inteiros=newint[5];inteiros[0]=1;inteiros[1]=2;inteiros[2]=3;inteiros[3]=4;inteiros[4]=5;
Veja que esse código é repetitivo e fácil de ser escrito de forma incorreta. Para facilitar nossotrabalho,oC#nosofereceumatalhoparacriare inicializaroconteúdodoarray.Sequiséssemosumarraydeinteirospreenchidocomosnúmerosde1a5,poderíamosutilizaroseguintecódigo:
int[]umAoCinco=newint[]{1,2,3,4,5};
Essasintaxepodeserutilizadaemarraysdequalquertipo.
11.1PARASABERMAIS—INICIALIZAÇÃODEARRAYS
92 11.1PARASABERMAIS—INICIALIZAÇÃODEARRAYS
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Qualdaslinhasaseguirinstanciaumarrayde10elementos?
int[]numeros=newint[9];
int[]numeros=newint[10];
int[]numeros=newint["dez"];
int[10]numeros=newint[10];
2. Imagineoarrayabaixo:
int[]numeros=newint[15];
Comoacessaroquintoelementonessalista?
numeros[3]
numeros[4]
numeros["quinto"]
numeros[5]
3. Dadoumarraynumero,comodescobrirseutamanho?
numero.Length
numero.Size
numero.Size()
JáconheceoscursosonlineAlura?
11.2EXERCÍCIOS
11.1PARASABERMAIS—INICIALIZAÇÃODEARRAYS 93
numero.Length()
numero.Capacity()
4. Agoravamosutilizararraysnoprojetodobancoparatrabalharmoscomdiversascontasaomesmotempo.Dentro da classe do formulário da aplicação, a classeForm1 criada peloVisual Studio,
vamosguardarumarraydecontasaoinvésdeumaúnicaconta.
publicpartialclassForm1:Form{//vamossubstituircontaporumarraydecontas.//Apaguealinha://privateContaconta;//Ecoloqueadeclaraçãodoarrayemseulugar:privateConta[]contas;
//restodaclasse}
NométodoForm1_Load,vamosinicializaroarraydecontasdoformulárioe,aoinvésdecriarmos
umaúnicaconta,vamoscriardiversascontaseguardá-lasdentrodoarray.
privatevoidForm1_Load(objectsender,EventArgse){//criandooarrayparaguardarascontascontas=newConta[3];
//vamosinicializaralgumasinstânciasdeConta.this.contas[0]=newConta();this.contas[0].Titular=newCliente("victor");this.contas[0].Numero=1;
this.contas[1]=newContaPoupanca();this.contas[1].Titular=newCliente("mauricio");this.contas[1].Numero=2;
this.contas[2]=newContaCorrente();this.contas[2].Titular=newCliente("osni");this.contas[2].Numero=3;}
Noformulário,parasabermosqualéacontaquedeveserexibida,colocaremosumnovocampodetextoondeousuárioescolheráqualéoíndicedaContaqueseráutilizada.Chameessecampode
textodetextoIndice.Alémdo campo de texto, adicione tambémumnovo botão que quando
clicadomostraráacontadoíndicequeousuárioselecionou.
Oseuformuláriodeveficarparecidocomodaimagem:
94 11.1PARASABERMAIS—INICIALIZAÇÃODEARRAYS
UtilizebotaoBuscacomo(Name)dessenovobotão.
QuandoousuárioclicarnobotaoBusca,precisamosmostraracontaquefoiselecionada:
privatevoidbotaoBusca_Click(objectsender,EventArgse){intindice=Convert.ToInt32(textoIndice.Text);Contaselecionada=this.contas[indice];textoNumero.Text=Convert.ToString(selecionada.Numero);textoTitular.Text=selecionada.Titular.Nome;textoSaldo.Text=Convert.ToString(selecionada.Saldo);}
No botão de depósito, precisamos depositar o valor na conta que foi escolhida pelo usuário notextoIndice.Emnossoexemplo,seousuáriodigitar1notextoIndice,precisamosfazero
depósitonacontadotitularmauricio(queestánaposição1doarray).
privatevoidbotaoDeposito_Click(objectsender,EventArgse){//primeiroprecisamosrecuperaroíndicedacontaselecionadaintindice=Convert.ToInt32(textoIndice.Text);
//edepoisprecisamosleraposiçãocorretadoarray.Contaselecionada=this.contas[indice];
doublevalor=Convert.ToDouble(textoValor.Text);selecionada.Deposita(valor);textoSaldo.Text=Convert.ToString(selecionada.Saldo);}
Faça o mesmo para a ação do botão de Saque. Depois de fazer todas as modificações, teste aaplicaçãofazendo,porexemplo,umdepósitonacontaqueestánoíndice0.
Tentefazeroperaçõesemdiferentes tiposdeconta.Vejaquedependendodotipodecontaquefoicadastradanoarray,teremosumresultadodiferenteparaasoperaçõesdesaqueedepósito.Notequeo código do formulário não precisa conhecer as contas que estão gravadas no array, ele precisa
11.1PARASABERMAIS—INICIALIZAÇÃODEARRAYS 95
apenasutilizarosmétodosqueestãonainterfacedeusodaconta.
Naaplicação,estamosgerenciandoascontascadastradasatravésdeumcampodetexto.Essaéumaabordagembemsimples,masquepossuidiversosproblemas:
Ocódigoesperaqueousuáriodigiteumnúmeronocampode texto.Seeledigitaruma letraouqualqueroutrocaracterenãonumérico,teremosumerro;Onúmerodigitadodeveserumíndiceválidodoarrayounovamenteteremosumerronocódigo.
Seria muito melhor se o usuário pudesse escolher uma conta cadastrada a partir de uma listagerenciada pela aplicação. Para implementarmos essa ideia, vamos utilizar um novo componente doWindowsFormchamadoComboBox.
Paraadicionarumcomboboxnoformulário,precisamosapenasabrirajanelaToolbox(Ctrl+W,
X)earrastarocomboboxparadentrodoformulário.
Para inserir os elementos que serão exibidos no combo box, precisaremos de uma variável queguardaareferênciaparaocomponente.Assimcomonocampodetexto,podemosdefinironomedessavariávelatravésdajanelaproperties.
Paraacessarajanelapropertiesdocombobox,cliquecomobotãodireitodomousenocombo
boxeselecioneaopçãoProperties.
Dentrodajanelaproperties,utilizaremosnovamenteocampo(Name)paradefinironomeda
variávelqueguardaráareferênciaparaocombobox.VamosutilizarcomboContas.
Agoraprecisamosmostrarostitularesdascontascomoitensdocombobox.Paraadicionarumnovoitemnocombobox,utilizamososeguintecódigo:
comboContas.Items.Add("Textoqueapareceránocombobox");
11.3ORGANIZANDOASCONTASCOMOCOMBOBOX
96 11.3ORGANIZANDOASCONTASCOMOCOMBOBOX
Logo,paramostrarostitularescomoitensdocombobox,utilizamososeguintecódigo;
comboContas.Items.Add(contas[0].Titular.Nome);comboContas.Items.Add(contas[1].Titular.Nome);
Oupodemosutilizarumforeach:
foreach(Contacontaincontas){comboContas.Items.Add(conta.Titular.Nome);}
Agoraquejáconseguimosmostrarocombobox,queremosqueaescolhadeumaopçãonocombo,façacomqueoformuláriomostreacontadotitularselecionado.
Para associar uma ação ao evento demudança de seleção do combo, precisamos apenas dar umduplocliquenocombobox.IssocriaráumnovométodonaclasseForm1:
privatevoidcomboContas_SelectedIndexChanged(objectsender,EventArgse){
}
Podemosrecuperarqualéo índice(começandodezero)do itemquefoiselecionadopelousuáriolendoapropriedadeSelectedIndexdocomboContas:
intindice=comboContas.SelectedIndex;
Esseíndicerepresentaqualéoelementodoarraydecontasquefoiselecionado,logo,podemosusá-lopararecuperaracontaquefoiescolhida:
Contaselecionada=contas[indice];
Depoisdedescobrirqualéacontaescolhida,vamosmostrá-lanoformulário:
textoTitular.Text=selecionada.Titular.Nome;textoSaldo.Text=Convert.ToString(selecionada.Saldo);textoNumero.Text=Convert.ToString(selecionada.Numero);
OcódigocompletodocomboContas_SelectedIndexChangedficadaseguinteforma:
11.3ORGANIZANDOASCONTASCOMOCOMBOBOX 97
privatevoidcomboContas_SelectedIndexChanged(objectsender,EventArgse){intindice=comboContas.SelectedIndex;Contaselecionada=contas[indice];textoTitular.Text=selecionada.Titular.Nome;textoSaldo.Text=Convert.ToString(selecionada.Saldo);textoNumero.Text=Convert.ToString(selecionada.Numero);}
1. Vamossubstituirocampodetextoqueselecionaacontaparaasoperaçõesporumcombobox.Noformulário da aplicação apague o campo textoIndice , o botaoBusca e o método
botaoBusca_Click.Essesdoiscomponentesserãosubstituídospelocombobox.
Agora abra a janelaToolboxdoVisualStudio e arraste umComboBox para a aplicação.Chame
componentedecomboContas.Seuformuláriodeveficarcomooaseguir:
Naaçãodecarregamentodoformulário,vamoscadastrarascontasdoarraydentrodocombobox.Paraisso,precisamoschamarométodoAdddapropriedadeItemsdocomboContas passando
qualéotextoquequeremosmostrarcomoopçãodocombobox.
privatevoidForm1_Load(objectsender,EventArgse){//códigodeinicializaçãodoarraydecontas
foreach(Contacontaincontas){comboContas.Items.Add("titular:"+conta.Titular.Nome);}}
Quando o usuário modificar o valor do combo box, queremos mudar a conta que é exibida no
11.4EXERCÍCIOS
98 11.2EXERCÍCIOS
formulário. Para criarmos o método que cuidará do evento de mudança de item selecionado docombo box, dê um duplo clique no componente. Isso criará dentro do Form1 o método
comboContas_SelectedIndexChanged:
privatevoidcomboContas_SelectedIndexChanged(objectsender,EventArgse){intindice=comboContas.SelectedIndex;Contaselecionada=this.contas[indice];textoNumero.Text=Convert.ToString(selecionada.Numero);textoTitular.Text=selecionada.Titular.Nome;textoSaldo.Text=Convert.ToString(selecionada.Saldo);}
Agora faça com que os botões Depositar e Sacar (métodos botaoDeposito_Click e
botaoSaque_Click,respectivamente)operemnacontaselecionadapelocombobox.
2. (Opcional)Vamosagoraadicionaralógicadetransferêncianoformulário.AdicioneumnovocomboboxnoformuláriochamadocomboDestinoTransferenciaeumnovobotãoque,quandoclicado,
transfere dinheiro da conta selecionada no comboContas para a conta selecionada no
comboDestinoTransferencia.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
11.4EXERCÍCIOS 99
CAPÍTULO12
Atéagora,temosemnossaaplicaçãoumcaixaeletrônicocomumnúmerofixodecontas,nessecapítulo,vamosfazerumnovoformulárioparacadastrarascontasnocaixaeletrônico.
Paranãocolocarmosaindamaiscamposnoformulárioprincipal,vamoscriarumnovoformulárionoprojeto.AbraoSolutionExplorer,cliquecomobotãodireitonoprojetoBancoeselecioneAdd
>NewItem.
Nanovajanela,selecioneaopçãoWindowsFormecoloqueFormCadastroConta.csnocampo
Name.Emseguida,cliquenobotãoAdd.
CADASTRODENOVASCONTAS
100 12CADASTRODENOVASCONTAS
Agoraqueterminamosdecriaronovoformulário,vamosadicionarumcampodetextoparaotitulardaconta (chamadotextoTitular) e umparaonúmeroda conta (chamadotextoNumero).Além
desses campos,precisaremos tambémdeumbotãoque, quandoclicado, realizaráo cadastrodanovaconta.Adicioneobotãoechame-odebotaoCadastro
Vamosdefiniraaçãodobotãodecadastrodessenovoformulário.Dêumduplocliquenobotãoqueacabamosdecriar.IssoabriránovamenteoeditordoVisualStudio:
publicpartialclassFormCadastroConta:Form{publicFormCadastroConta(){InitializeComponent();}
privatevoidbotaoCadastro_Click(objectsender,EventArgse){
}
12CADASTRODENOVASCONTAS 101
}
Naaçãodobotão,queremoscriarumanova instânciadeconta,ContaCorrente por exemplo, e
depoispreencherosseusdados:
privatevoidbotaoCadastro_Click(objectsender,EventArgse){ContanovaConta=newContaCorrente();novaConta.Titular=newCliente(textoTitular.Text);novaConta.Numero=Convert.ToInt32(textoNumero.Text);}
Agora que inicializamos a conta, precisamos cadastrá-la no array que está na classe Form1 .
Precisamos, portanto, acessar a instância de Form1 a partir de FormCadastroConta. Queremos
garantirque,naconstruçãodoFormCadastroConta, teremosainstânciadeForm1,portantovamos
modificaroconstrutordaclasseparareceberoformulárioprincipal:
publicpartialclassFormCadastroConta:Form{privateForm1formPrincipal;
publicFormCadastroConta(Form1formPrincipal){this.formPrincipal=formPrincipal;InitializeComponent();}
//Açãodecadastrodeconta}
Precisamos colocar a conta criada no array que contém todas as contas cadastradas que está noformulárioprincipaldaaplicação.
Parafazerisso,podemosmudaravisibilidadedoatributo(deixarocontaspúblico),masissoéumaviolaçãodeencapsulamento,estamosclaramentevendoosdetalhesdeimplementaçãodaclasseForm1.
Portanto, precisamos colocar ummétodo que adiciona uma nova conta na interface de uso da classeForm1.
publicpartialclassForm1{//Esseéomesmoarrayquecolocamosnocapítulodearrays.privateConta[]contas;
//outrosmétodosdeForm1
publicvoidAdicionaConta(Contaconta){//implementaçãodométodoadicionaconta}}
Inicialmente,temoszerocontascadastradasnosistemaeaprimeiracontaserácolocadanaposiçãozero, no cadastro da segunda, temos 1 conta já cadastrada e a próxima será colocada na posição 1.Repare que sempre colocamos a conta na posição equivalente ao número de contas que já estãocadastradas. Então para implementarmos o AdicionaConta, precisaremos de um novo atributo no
102 12CADASTRODENOVASCONTAS
formulárioquerepresentaonúmerodecontasquejáforamcadastradas.
publicpartialclassForm1{privateConta[]contas;//guardaonúmerodecontasquejáforamcadastradasprivateintnumeroDeContas;
//outrosmétodosdeForm1
publicvoidAdicionaConta(Contaconta){this.contas[this.numeroDeContas]=conta;this.numeroDeContas++;}}
Alémdecolocaracontanoarray,precisamostambémregistraracontanocomboContas.
publicvoidAdicionaConta(Contaconta){this.contas[this.numeroDeContas]=conta;this.numeroDeContas++;comboContas.Items.Add("titular:"+conta.Titular.Nome);}
Precisamosutilizaressenovométododentrodoformuláriodecadastroparacadastraranovaconta:
privatevoidbotaoCadastro_Click(objectsender,EventArgse){ContanovaConta=newContaCorrente();novaConta.Titular=newCliente(textoTitular.Text);novaConta.Numero=Convert.ToInt32(textoNumero.Text);
this.formPrincipal.AdicionaConta(novaConta);}
Agoraquetemostodaalógicapronta,precisamosapenascolocarumbotãonoformulárioprincipalqueabreoformuláriodecadastrodenovaconta.Chamá-lo-emosdebotaoNovaConta:
12CADASTRODENOVASCONTAS 103
Na ação desse botão, precisamos instanciar o FormCadastroConta passando a instância do
formulário principal. Dê um duplo clique no botão que acabamos de incluir no formulário paraimplementarsuaação:
privatevoidbotaoNovaConta_Click(objectsender,EventArgse){//thisrepresentaainstânciadeForm1queestásendoutilizadapelo//WindowsFormFormCadastroContaformularioDeCadastro=newFormCadastroConta(this);}
Paramostraroformulário,utilizaremosométodoShowDialogdoFormCadastroConta
privatevoidbotaoNovaConta_Click(objectsender,EventArgse){FormCadastroContaformularioDeCadastro=newFormCadastroConta(this);formularioDeCadastro.ShowDialog();}
Comissoterminamosocadastrodenovascontasnaaplicação.
TemososeguintecódigonométodoqueéexecutadonoLoaddoformulárioprincipal:
privatevoidForm1_Load(objectsender,EventArgse){this.contas=newConta[3];
//vamosinicializaralgumasinstânciasdeConta.this.contas[0]=newConta();this.contas[0].Titular=newCliente("victor");this.contas[0].Numero=1;
this.contas[1]=newContaPoupanca();this.contas[1].Titular=newCliente("mauricio");this.contas[1].Numero=2;
this.contas[2]=newContaCorrente();this.contas[2].Titular=newCliente("osni");this.contas[2].Numero=3;
foreach(Contacontaincontas){comboContas.Items.Add(c.Titular.Nome);}}
Veja que estamos colocando as contas diretamente na posição correta do array,mas não estamosatualizando o atributo numeroDeContas que incluímos no formulário. Além disso, inicializamos o
arraycomapenas3posições,logonãotemosmaisespaçoparacadastrarasnovascontas.
Para resolvero segundoproblema,precisamos simplesmentemodificaro tamanhodoarrayque éalocadopara,porexemplo,aceitaratédezcontas:
12.1UTILIZANDOOADICIONACONTANOLOADDOFORMULÁRIO
104 12.1UTILIZANDOOADICIONACONTANOLOADDOFORMULÁRIO
privatevoidForm1_Load(objectsender,EventArgse){this.contas=newConta[10];
//restodocódigodométodo}
Pararesolveroprimeiroproblema,odeatualizarovalordoatributonumeroDeContas,precisamos
apenasdeumincrementodepoisdeadicionarcadaumadascontasnoarray:
privatevoidForm1_Load(objectsender,EventArgse){this.contas=newConta[10];
//vamosinicializaralgumasinstânciasdeConta.this.contas[0]=newConta();this.contas[0].Titular=newCliente("victor");this.contas[0].Numero=1;this.numeroDeContas++;
this.contas[1]=newContaPoupanca();this.contas[1].Titular=newCliente("mauricio");this.contas[1].Numero=2;this.numeroDeContas++;
this.contas[2]=newContaCorrente();this.contas[2].Titular=newCliente("osni");this.contas[2].Numero=3;this.numeroDeContas++;
foreach(Contacontaincontas){comboContas.Items.Add(c.Titular.Nome);}}
Vejaquenocódigodométodoestamoscadastrandoacontanoarray, incrementandoonúmerodecontase,porfim,adicionandoacontanocomboContas.Essecódigofazexatamenteomesmotrabalho
queométodoAdicionaContaquecriamosnessecapítulo.Então,podemosreutilizá-lo:
privatevoidForm1_Load(objectsender,EventArgse){this.contas=newConta[10];
//vamosinicializaralgumasinstânciasdeConta.Contac1=newConta();c1.Titular=newCliente("victor")c1.Numero=1;this.AdicionaConta(c1);
Contac2=newContaPoupanca();c2.Titular=newCliente("mauricio");c2.Numero=2;this.AdicionaConta(c2);
Contac3=newContaCorrente();c3.Titular=newCliente("osni");c3.Numero=3;this.AdicionaConta(c3);}
12.1UTILIZANDOOADICIONACONTANOLOADDOFORMULÁRIO 105
ReparequecomessecódigoométodoForm1_Loadnãoprecisamaissepreocuparcomosdetalhes
de comoas contas são armazenadas e nemde comoadicionar a conta nocomboContas.Todo esse
conhecimentoficaencapsuladonométodoAdicionaConta.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
1. Vamos criar um novo formulário que será responsável por fazer o cadastro de novas contas naaplicação.NajaneladoSolutionExplorer,cliquecomobotãodireitononomedoprojetoeescolhaaopçãoAdd>NewItem.
Najaneladenovoitem,escolhaaopçãoWindowsFormeutilizeFormCadastroContacomonome
do novo formulário que será criado.Dentro desse formulário, coloque dois campos de texto, umchamadotextoNumeroeoutrochamadotextoTitular.Alémdisso,adicionetambémumnovo
botão nesse formulário. Esse será o botão que cadastrará a nova conta. Chame o botão debotaoCadastro.
2. Vamos agora implementar a ação do botão de cadastro desse novo formulário (oFormCadastroConta).Dêumduplocliquenobotãoqueacabamosdeadicionar.Dentrodaaçãodo
botão, leia as informações que foram digitadas no formulário e utilize-as para criar uma novaContaCorrente:
privatevoidbotaoCadastro_Click(objectsender,EventArgse){ContaCorrentenovaConta=newContaCorrente();novaConta.Titular=newCliente(textoTitular.Text);novaConta.Numero=Convert.ToInt32(textoNumero.Text);}
AgoralocalizeoconstrutordoFormCadastroConta:
Seuslivrosdetecnologiaparecemdoséculopassado?
12.2EXERCÍCIOS
106 12.2EXERCÍCIOS
publicFormCadastroConta(){InitializeComponent();}
Faça comque esse construtor recebaumargumentodo tipoForm1 chamadoformPrincipal.
Guardeovalorquefoipassadodentrodeumnovoatributo.Seucódigodeveficarparecidocomoquesegue:
publicpartialclassFormCadastroConta:Form{privateForm1formPrincipal;
publicFormCadastroConta(Form1formPrincipal){this.formPrincipal=formPrincipal;InitializeComponent();}
privatevoidbotaoCadastro_Click(objectsender,EventArgse){ContaCorrentenovaConta=newContaCorrente();novaConta.Titular=newCliente(textoTitular.Text);novaConta.Numero=Convert.ToInt32(textoNumero.Text);}}
3. Dentrodaclassedoformulárioprincipal,arquivoForm1.cs,adicioneumnovoatributochamado
numeroDeContas e umnovométodo chamadoAdicionaConta que receberá uma conta como
argumentoeacadastraránoarraydecontasdoformulário:
publicpartialclassForm1:Form{privateintnumeroDeContas;
//EssearrayjáestavadeclaradonaclasseprivateConta[]contas;
//implementaçãodasaçõesdoformulário
publicvoidAdicionaConta(Contaconta){this.contas[this.numeroDeContas]=conta;this.numeroDeContas++;comboContas.Items.Add("titular:"+conta.Titular.Nome);}}
4. Abranovamenteocódigodobotãodoformuláriodecadastrodenovascontas.DentrodométodobotaoCadastro_Click,utilizeoAdicionaContadoformPrincipalpassandoacontaquefoi
criadaanteriormente.
privatevoidbotaoCadastro_Click(objectsender,EventArgse){ContaCorrentenovaConta=newContaCorrente();novaConta.Titular=newCliente(textoTitular.Text);novaConta.Numero=Convert.ToInt32(textoNumero.Text);
12.2EXERCÍCIOS 107
this.formPrincipal.AdicionaConta(novaConta);}
5. Dentro do formulário principal da aplicação (Form1.cs), coloque um novo botão que quando
clicadomostraráoformuláriodecadastro.ChameessenovobotãobotaoNovaConta.
privatevoidbotaoNovaConta_Click(objectsender,EventArgse){FormCadastroContaformularioCadastro=newFormCadastroConta(this);formularioCadastro.ShowDialog();}
6. Antesdetestarocadastrodecontasqueacabamosdeimplementar,abraométodoForm1_Loaddo
formulárioprincipalecadastreascontaspadrãodosistemautilizandoométodoAdicionaConta
quecriamosemumexercícioanterior:
privatevoidForm1_Load(objectsender,EventArgse){this.contas=newConta[10];
//vamosinicializaralgumasinstânciasdeConta.Contac1=newConta();c1.Titular=newCliente("victor")c1.Numero=1;this.AdicionaConta(c1);
Contac2=newContaPoupanca();c2.Titular=newCliente("mauricio");c2.Numero=2;this.AdicionaConta(c2);
Contac3=newContaCorrente();c3.Titular=newCliente("osni");c3.Numero=3;this.AdicionaConta(c3);}
Depoisdefazeressamodificaçãofinal,executeaaplicaçãoetesteocadastro.
7. (Opcional)Noformuláriodecadastro,adicioneumcombobox(chamadocomboTipoConta) que
permitaaescolhadotipodecontaqueserácadastrado.
8. (Desafio)Noprojetoestamosatualmenteutilizandoumarraydecontascomumtamanhofixoeporissosópodemoscadastrarumnúmerolimitadodecontas.ModifiqueométodoAdicionaContada
classeForm1paraqueeleaceiteumnúmeroilimitadodecontas.
108 12.2EXERCÍCIOS
CAPÍTULO13
Em nosso banco os clientes podem ter dois tipos de conta até o momento: conta corrente ou contapoupança.Parainstanciarestestiposdeconta,poderíamosusaroseguintecódigo:
//InstanciarumanovacontacorrenteContaCorrentecontaCorrente=newContaCorrente();
//InstanciaumanovacontapoupançaContaPoupancacontaPoupanca=newContaPoupanca();
Nos capítulos anteriores, aprendemos que essas duas classes têm muito em comum, ambas sãocontas.Nãoapenastêmatributosemcomum,mastambémcomportamentos.Paraevitararepetiçãodocódigoemambasasclasses,vimoscomoisolarestecódigorepetidoemumaclasseConta,efazercom
queasclassesContaCorrenteeContaPoupancaherdemdessaclassemãetodoocódigoemcomum.
Além da reutilização de código, também vimos a possibilidade de escrever métodos que podemreceber argumentos tanto do tipo ContaCorrente quanto do tipo ContaPoupanca , utilizando
polimorfismo.Bastafazermososmétodosreferenciaremotipomaisgenérico,nocaso,Conta:
publicclassTotalizadorDeContas{//...publicvoidSoma(Contaconta){//...}}
Masoqueacontecequandoexecutamosaseguintelinha:
Contac=newConta();
CriamosumnovoobjetodotipoConta.Masesseobjetofazalgumsentidoparanossasregrasde
negócio?Éumacontagenérica,nãosendonemcontacorrenteenempoupança.
Nestecaso,nãodeveríamospermitirainstanciaçãodeobjetosConta.
Contaéapenasumaideiaemnossodomínio,umaformagenéricadereferenciarmososdoistipos
de conta que realmente existem em nosso sistema, ContaCorrente e ContaPoupanca. Podemos
evitaracriaçãodeobjetosdotipoContadefinindoaclassecomoabstrata:
publicabstractclassConta
CLASSESABSTRATAS
13CLASSESABSTRATAS 109
{//...}
Destaforma,nãopodemosmaiscriarobjetosdotipoConta,maspodemosaindausarvariáveisdo
tipoconta,parareferenciarobjetosdeoutrostipos:
Contaconta=newConta();//nãocompila,nãopodecriarobjetosabstratos
Contacc=newContaCorrente();//pode,objetoédotipoContaCorrente
Contacp=newContaPoupanca();//pode,objetoédotipoContaPoupanca
ReparequeocalculonecessáriopararealizarumsaqueédiferenteemcadaumdostiposdeConta.
SabemosqueumacontadeveterummétodoSaca,masa implementaçãodestemétododependede
regras específicas de cada tipo diferente de conta em nosso sistema. Uma solução possível seriaimplementá-losemfazernada,masdizendoqueelepodesersobrescrito(virtual):
publicabstractclassConta{publicvirtualvoidSaca(doublevalor){//nãofaznada}//...}
EmanterocódigoSacaoriginalnasclassesfilhas,dizendoqueelessobrescrevem(override)o
métodonaclassepai:
publicclassContaCorrente:Conta{publicoverridevoidSaca(doublevalor){this.Saldo-=(valor+0.10);}//...}
publicclassContaPoupanca:Conta{publicoverridevoidSaca(doublevalor){this.Saldo-=valor;}//...}
Desejamosquetodaclassefilhaimplementesuaprópriaversãodométodo,comocomportamentoreferenteaotipodaconta.MasseesquecermosdesobrescreverométodoSacaemumasubclasse,o
métodoherdadoda classeConta será executado, que não faz nada.Não queremos isso!Queremos
obrigarasclassesfilhaaimplementarométodoSaca.
Podemosobrigartodasasclassesfilhasasobrescreveremummétodonaclassemãe,bastadeclararessemétodocomomodificadorabstractaoinvésdevirtual.Todavezquemarcamosummétodo
110 13CLASSESABSTRATAS
comomodificadorabstract,eleobrigatoriamentenãopodeterumaimplementaçãopadrão:
publicabstractclassConta//marcandoqueaclasseestáincompleta{publicabstractvoidSaca(doublevalor);//marcandoqueométodoestáincompleto}
Comessamodificação,ométodoSacapassaarepresentarapenasumaideia,queprecisadeuma
implementação concreta nas classes filhas. Caso não implementemos esse método na classe filha, ocompilador emitirá um erro, avisando da obrigatoriedade de sobrescrever este método. Então seimplementássemos,porexemplo,aclasseContaPoupancasemdefiniraimplementaçãodoSaca, o
códigodaclassenãocompilará:
publicclassContaPoupanca:Conta{//EssaclassenãocompilapoisnãocolocamosaimplementaçãoparaoSaca}
Podemosterumaclasseabstratasemnenhummétodoabstrato,masnãoocontrário.Seaclassetempelomenosummétodoabstrato,eladeveserabstratatambémpoiscomoométodoestáincompleto,aclassenãoestácompleta.
1. Transforme a classe Conta em uma classe abstrata. Repare que agora teremos um erro de
compilação em todos os pontos do código em que tentamos instanciar o tipo Conta. Por quê?
Modifiqueocódigodasuaaplicaçãoparaqueacontanãoseja instanciada,assimcorrigiremososerrosdecompilação.Nãoseesqueçadesempretestaroseucódigo.
2. ReparequeherdamososmétodosSacaeDepositadaclasseConta,porémcadatipodeConta
sobrescreve essesmétodos, logo eles são bons candidatos paramétodos abstratos. Transforme osmétodosSacaeDepositaemmétodosabstratos,reparequecomissotodasasclassesfilhassão
obrigadasadarumaimplementaçãoparaessesmétodos.
13.1EXERCÍCIOS
13.1EXERCÍCIOS 111
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Agoraéamelhorhoradeaprenderalgonovo
112 13.1EXERCÍCIOS
CAPÍTULO14
Nosso banco agora suporta Contas de Investimento. Já sabemos como fazer: basta herdar da classeConta:
publicclassContaInvestimento:Conta{//comportamentosespecíficosdacontainvestimento}
Por lei, uma vez por ano devemos pagar um tributo ao governo relacionado às contas deinvestimentoecontasdepoupança.OmesmonãoacontececomumasimplesContaCorrente.
Para resolver esse problema, podemos criar ummétodo em ambas as classes que calcula o valordessetributo.Porexemplo:
publicclassContaPoupanca:Conta{//outrosmetodos
publicdoubleCalculaTributo(){returnthis.Saldo*0.02;}}publicclassContaInvestimento:Conta{//outrosmetodos
publicdoubleCalculaTributo(){returnthis.Saldo*0.03;}}
Excelente.OsmétodossóficamnasContasquerealmentesofremessetributo.
Agora, a próxima funcionalidade é a geração de um relatório, no qual devemos imprimir aquantidade total de tributos pagos por todas as Contas Investimento ou Poupanca do nosso banco.Precisamosdeumaclassequeacumulaovalordetodosostributosdetodasascontasdobanco.Esseéumproblemaparecidocomoquejátivemosantes:
publicclassTotalizadorDeTributos{publicdoubleTotal{get;privateset;}
publicvoidAcumula(ContaPoupancacp){Total+=cp.CalculaTributo();}
INTERFACES
14INTERFACES 113
publicvoidAcumula(ContaInvestimentoci){Total+=ci.CalculaTributo();}}
Pronto.AgorabastapassarmosContaInvestimentoouContaPoupancaenossaclasseacumulará
ovalordotributo.Reparequetodavezqueumanovacontasofrerumtributo,precisaremoslembrardevoltarnaclasseTotalizadorDeTributosecriarumnovométodoAcumula().
Noscapítulosanteriores,resolvemosissousandopolimorfismo.Seaclassepaipossuirométodoemcomum,entãobastarecebermosumareferênciaprotipopai:
publicclassTotalizadorDeTributos{publicdoubleTotal{get;privateset;}
publicvoidAcumula(Contac){Total+=c.CalculaTributo();}}
MasseráquefazsentidocolocarométodoCalculaTributo()naclasseConta?
publicabstractclassConta{//restodaclasseaquipublicabstractdoubleCalculaTributo();}
Nem todas as Contas são tributáveis. Se fizermos isso, a classe ContaCorrente ganhará esse
método,maselanãosofretributo!
Precisamos achar umamaneira de "achar um pai em comum" apenas para aContaCorrente e
ContaInvestimento.ClassesemC#nãopodemterdoispais.Masoquepodemosfazerédizerparao
compilador quegarantiremos a existência dométodoCalculaTributo() nas classes que chegarem
paraométodoAcumula().
Comofazemosisso?Simples.Fazemosaclasse"assinar"umcontrato!Nessecaso,queremosassinaro contrato que fala que somos Tributáveis. Contratos no C# são conhecidos como interfaces. Adeclaração de uma interface é praticamente igual a de uma classe, porém utilizamos a palavrainterfaceaoinvésdeclass.
publicinterfaceTributavel{//códigodainterface}
AconvençãodenomesdoC#paraumainterfaceéseguiramesmaconvençãodenomenclaturadeclassesporémcomumInocomeçodonome:
publicinterfaceITributavel{
}
114 14INTERFACES
Éumaboapráticacolocarocódigodainterfacedentrodeumarquivoseparadocomomesmonomedainterface.Porexemplo,ainterfaceITributavelficarianoarquivoITributavel.cs.Dentroda
interface,queremoscolocaradeclaraçãodométodoCalculaTributo().Métodosdeclaradosemuma
interface nunca possuem implementação e sempre são públicos. A declaração da interfaceITributavelcomométodoCalculaTributo()ficadaseguinteforma:
//ArquivoITributavel.cs
publicinterfaceITributavel{doubleCalculaTributo();}
QueremosfazercomqueacontapoupançaassineocontratoITributavelqueacabamosdecriar,
paraisso,precisamoscolocaronomedainterfacequequeremosimplementarlogoapósadeclaraçãodaclassepai:
//ArquivoContaPoupanca.cs
publicclassContaPoupanca:Conta,ITributavel{//ImplementaçãodosmétodosdaContaPoupanca}
ComoainterfaceITributaveldeclaraométodoCalculaTributo(), toda classe que assina a
interface é obrigada a dar uma implementação para essa funcionalidade, se não implementarmos ométododainterface,aclassenãocompilará.
publicclassContaPoupanca:Conta,ITributavel{//restodaclasseaqui
//métodoquesouobrigadoaimplementarpublicdoubleCalculaTributo(){returnthis.Saldo*0.02;}}
Repare que, para implementarmos o método da interface, não podemos utilizar a palavraoverride , ela é reservada para a sobrescrita de métodos da Herança. A mesma coisa para a
ContaInvestimento:
publicclassContaInvestimento:Conta,ITributavel{//restodaclasseaqui
//métodoquesouobrigadoaimplementarpublicdoubleCalculaTributo(){returnthis.Saldo*0.03;}}
14INTERFACES 115
Alémdisso,podemosfazercomqueumaclasseassineumainterfacesemherdardeoutraclasse.Porexemplo, o banco também trabalha com seguros de vida que também são tributáveis, logo podemosrepresentaressaclassecomoseguintecódigo:
publicclassSeguroDeVida:ITributavel{publicdoubleCalculaTributo(){//implementaçãodoCalculaTributo}}
Dessa forma, podemos dizer que a classe TotalizadorDeTributos recebe um ITributavel
qualquer.Opolimorfismofuncionacominterfaces!
publicclassTotalizadorDeTributos{publicdoubleTotal{get;privateset;}
publicvoidAcumula(ITributavelt){Total+=t.CalculaTributo();}}
Excelente!Vejaquecominterfacesconseguimosfazercomqueumconjuntodeclassesimplementeosmesmosmétodos.
Interfaces são bemmais simples do que classes. Elas não tem atributos e seusmétodos não temimplementação.Ainterfaceapenasnosgarantequeométodoexistiránaquelaclasse.Poressemotivo,apesardeC#não suportar herançamúltipla (ser filhodemaisdeumaclasse), podemos implementarquantasinterfacesquisermos.Bastacolocarumanafrentedaoutra:
publicclassContaInvestimento:Conta,ITributavel,OutraInterfaceQualquer{//implementaosmétodosdasinterfacesTributaveleOutraInterfaceQualquer}
Quando uma classe utiliza tanto herança quanto interfaces, precisamos sempre declarar qual é aclassepaiedepoisasinterfaces,assimcomofizemosnaContaPoupanca:
//Reparequeprimeirocolocamosaclassepai(Conta)edepoisasinterfaces.//Semudarmosaordem,ocódigonãocompilará.publicclassContaPoupanca:Conta,ITributavel{//implementação}
Acostume-secominterfaces.Daquiprafrente,veremosasváriasinterfacesqueexistemnoC#!
1. O banco precisa gerenciar os impostos que serão pagos por seus produtos. Para resolver esseproblema,criaremosumanovainterfacechamadaITributavel.Paracriarainterface,cliquecom
14.1EXERCÍCIOS
116 14.1EXERCÍCIOS
obotãodireitodomousenonomedoprojetoeescolhaaopçãoAdd>NewItem(omesmoque
utilizamos para criar o formulário de cadastro). Na janela de novo item, escolha a opçãoInterfaceecoloqueonomeITributavel:
Faça com que essa interface declare um método chamado CalculaTributos que não recebe
nenhumargumentoedevolveumdoublequerepresentaovalordoimpostoquedeveserpago.
Ocódigodainterfacedeveficarparecidocomoseguinte:
publicinterfaceITributavel{doubleCalculaTributos();}
2. Oqueacontecesetentarmosinstanciarumainterface?
ITributavelt=newITributavel();
Errodecompilação.Interfacesnãotemimplementaçãoe,logo,nãopodemserinstanciadas.
Ocódigocompila,masoobjetonãofaznada.
OC#buscaaleatoriamenteumaclassequeimplementaessainterfaceeainstancia.
3. FaçacomqueaclasseContaCorrente implementea interfaceITributavel que acabamosde
criar,porémaindanãoimplementeométodoCalculaTributos.Tenteexecutarocódigo.Oque
aconteceu?4. ComoaContaCorrenteassinaainterfaceITributavel,precisamoscolocarumaimplementação
14.1EXERCÍCIOS 117
para ométodo CalculaTributos dentro da classe, se não o código do projeto não compilará.
ImplementeométodoCalculaTributosdaContaCorrente, façacomqueaContaCorrente
pague5%deseusaldocomoimposto.5. CrieumanovaclassenobancochamadaSeguroDeVidaefaçacomqueessaclasseimplementea
interfaceITributavel.OmétodoCalculaTributosdoSeguroDeVidadevedevolverumvalor
constantede42reais.
6. Agoravamosadicionarumnovobotãonoformulárioquecalcularáosimpostosdobanco.Chame-odebotaoImpostos. No código desse botão, teste o método CalculaTributos em diferentes
situações,porexemplo:
privatevoidbotaoImpostos_Click(objectsender,EventArgse){ContaCorrenteconta=newContaCorrente();conta.Deposita(200.0);
MessageBox.Show("impostodacontacorrente="+conta.CalculaTributos());ITributavelt=conta;
MessageBox.Show("impostodacontapelainterface="+t.CalculaTributos());
SeguroDeVidasv=newSeguroDeVida();MessageBox.Show("impostodoseguro="+sv.CalculaTributos());
t=sv;MessageBox.Show("impostodoseguropelainterface"+t.CalculaTributos());}
Depoisdeimplementarseustestes,tenteclicarnobotãoparaveroqueacontece.
7. (Opcional) Crie uma nova classe chamada TotalizadorDeTributos, que será responsável por
acumularosimpostosdediferentesprodutostributáveisdobanco:
publicclassTotalizadorDeTributos{publicdoubleTotal{get;privateset;}
publicvoidAdiciona(ITributavelt){this.Total+=t.CalculaTributos();}}
Depoisdecriaressaclasse,modifiqueocódigodobotãodoexercíciopassadoparaqueeleutilizeaclassequeacabamosdecriarparacalcularototaldeimpostos.Porexemplo:
privatevoidbotaoImpostos_Click(objectsender,EventArgse){ContaCorrenteconta=newContaCorrente();conta.Deposita(200.0);
SeguroDeVidasv=newSeguroDeVida();
TotalizadorDeTributostotalizador=newTotalizadorDeTributos();totalizador.Adiciona(conta);
118 14.1EXERCÍCIOS
MessageBox.Show("Total:"+totalizador.Total);totalizador.Adiciona(sv);MessageBox.Show("Total:"+totalizador.Total);}
8. (Desafio) Pesquise sobre a palavra is do C# no seguinte link http://msdn.microsoft.com/en-us/library/scekt9xw.aspx e depois tente modificar o código o botão para que ele seja capaz decalcularautomaticamenteoimpostodetodasascontascorrentesqueestãocadastradasnoarraydecontasdaaplicação.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
EditoraCasadoCódigocomlivrosdeumaformadiferente
14.1EXERCÍCIOS 119
CAPÍTULO15
Precisamosagoraguardaraquantidadedecontascorrenteexistentesnosistema.Umadasmaneirasdefazerissoégerenciarototaldecontaseadicionar1unidadenessetotaltodavezquecriarmosumanovaconta:
inttotalDeContasCorrente=0;
//...
ContaCorrentenovaConta=newContaCorrente();totalDeContasCorrente++;
Contudo, utilizando essa abordagem, um desenvolvedor pode esquecer de alterar a variáveltotalDeContasCorrente apóscriarumanovaContaCorrente, gerandoumerrono sistema.Para
evitarisso,seriamelhorqueaprópriaclassecontrolasseototaldecontascriadas.Umaprimeiraideiaseriaguardarumatributocomototaldecontascriadasnaclassee,noseupróprioconstrutor,adicionarumaunidadenesseatributo:
publicclassContaCorrente:Conta{//OutrosatributosdaclasseprivateinttotalDeContas=0;
publicContaCorrente(){this.totalDeContas++;}
//Métodosdaclasse}
QualseriaovalordoatributototalDeContassefossemcriadasduascontas?
ContaCorrenteprimeira=newContaCorrente();ContaCorrentesegunda=newContaCorrente();
Ambasascontasapresentariamovalor1noseuatributototalDeContas.Issoaconteceporqueo
atributototalDeContas é diferente para cadaobjetoque instanciamos, isto é, o atributopertence a
cadaobjeto.
Oquedesejamoséquequetivéssemosumatributocompartilhadoemtodososobjetosdaclasse,ouseja,queoatributopertençaàclasseaoinvésdosobjetos.
MÉTODOSEATRIBUTOSESTÁTICOS
120 15MÉTODOSEATRIBUTOSESTÁTICOS
Estesatributosrecebemonomedeatributosdaclasseouatributosestáticose,emC#,paracriarumatributoestáticobastacolocarapalavrastaticnadeclaraçãodoatributo:
publicclassContaCorrente:Conta{privatestaticinttotalDeContas=0;//restodocódigoexistente}
Comisso,onossoconstrutorficaria:
publicclassContaCorrente:Conta{privatestaticinttotalDeContas=0;publicContaCorrente{ContaCorrente.totalDeContas++;}//restodocódigoexistente}
Opróximopassoécriarumcontrolequemostraqualonúmerodapróximacontadisponível,istoé,ototaldecontasmaisum.Comisso,criaríamosummétodopúblicoquedevolvaototalDeContas+
1:
publicclassContaCorrente:Conta{privatestaticinttotalDeContas=0;publicContaCorrente{ContaCorrente.totalDeContas++;}publicintProximaConta(){returnContaCorrente.totalDeContas+1;}//restodocódigoexistente}
Mascomoométodopertenceaoobjeto (nãoéestático)enãoàclasse, temosque instanciarumacontaparapoderacessá-lo:
//aquiototalé0,imprimiria1,quedesejamos
ContaCorrenteconta=newContaCorrente();conta.ProximaConta();//imprime2,poisjácriamosuma
PercebaqueprecisamoscriarumnovoobjetoparachamarométodoProximaConta.Mas,aocriar
umanovaconta,ovalordototalDeContasjáfoialterado.Paraevitarisso,ométodoprecisapertencer
àclasseaoinvésdoobjeto.Demaneirasemelhanteaumatributoestático,colocandoapalavrastatic
aodeclararummétodo,estesetornaestático:
publicclassContaCorrente:Conta{//restodocódigoexistente
15MÉTODOSEATRIBUTOSESTÁTICOS 121
publicstaticintProximaConta(){returnContaCorrente.totalDeContas+1;}}
Eparausaressenovométodo:
intproxima=ContaCorrente.ProximaConta();
1. Nocadastrodecontas,estamospedindoonúmeroqueserácadastradonanovaconta,masemnossobanco,duascontasnãopodemteromesmonúmero.Paragarantirmosqueonúmerodascontasseráúnico,podemosutilizarostaticdoC#paracriarumcontadordeinstânciasdecontasqueforam
criadas.
DeclarenaclassecontaumnovoatributoestáticochamadonumeroDeContasquecontaráquantas
contasforamcriadasnaaplicação.AdicioneumconstrutornaclassContaquenãorecebenenhum
argumentoegeraoNumeroutilizandoovalordoatributoestáticonumeroDeContas:
publicabstractclassConta{privatestaticintnumeroDeContas;
publicConta(){Conta.numeroDeContas++;this.Numero=Conta.numeroDeContas;}
//Restodaclassecontinuaigual}
2. Abraoformuláriodecadastrodenovascontas.Procurenocódigodesseformulárioaaçãodobotãoque cadastra a nova conta utilizando os dados digitados pelo usuário, métodobotaoCadastro_Click.Dentrodessemétodo,apaguea linhaqueatribuionúmerodacontaque
serácriada.Essenúmeroagoraégeradopelaprópriaclasseconta.
3. Agoraqueacontageraseunúmero,nãoémaispossívelparaousuáriosaberqualseráonúmerodacontaqueserácadastrada.Pararesolvermosesseproblema,vamosmostrarqualseráonúmerodapróximacontanocampotextoNumerodoformuláriodecadastro.
OnumeroDeContaséumatributoestáticoeprivadodentrodaclasseConta, logoo formulário
não pode acessar o valor desse atributo paramostrá-lo. Crie um novométodo estático na classeContachamadoProximoNumeroqueseráresponsávelpordevolveronúmerodapróximaConta
queserácriadapelaaplicação.
ComoovalordoatributonumeroDeContaséincrementadoapenasquandooconstrutordaConta
15.1EXERCÍCIOSOPCIONAIS
122 15.1EXERCÍCIOSOPCIONAIS
é executado, para exibir qual será o próximo número da conta que será criada, retorne onumeroDeContas+1:
publicstaticintProximoNumero(){returnnumeroDeContas+1;}
4. Agoravamosfazeroformuláriodecadastromostraronúmerodapróximacontaparaousuário.DêumduplocliquenoformuláriodecadastroparafazercomqueoVisualStudiocrieométodoqueserá executado no load do formulário. Dentro desse método, mostre o resultado do métodoConta.ProximoNumero()nocampotextoNumero.
privatevoidFormCadastroConta_Load(objectsender,EventArgse){textoNumero.Text=Convert.ToString(Conta.ProximoNumero());}
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Algumasvezescriamosclassesquecontêmapenasmétodosauxiliaresestáticos.Comoessasclassesnão possuem métodos nem propriedades de instâncias, não queremos permitir que elas sejaminstanciadas. Nessas situações, podemos utilizar as classes estáticas do C#. Para criar uma classeestática,precisamosapenasutilizarapalavrastaticemsuadeclaração:
publicstaticclassFunções{//implementação}
Quando uma classe é declarada como estática, ela não pode ser instanciada e nem herdada e,portanto,sópodepossuirmembrosestáticos.
publicstaticclassFuncoes
JáconheceoscursosonlineAlura?
15.2PARASABERMAISCLASSESESTÁTICAS
15.2PARASABERMAISCLASSESESTÁTICAS 123
{//Essemétodoéválidodentrodeumaclasseestática.publicstaticboolMetodoEstatico(){//implementação}
//Essemétodonãoéválidodentrodeumaclasseestática.publicboolMetodoInstancia(){//implementação}}
124 15.2PARASABERMAISCLASSESESTÁTICAS
CAPÍTULO16
VoltandoànossaclasseContaPoupanca,umdosseusmétodoséoSaca.Setentarmossacarumvalor
superior ao saldodo cliente, ométodonãopermitirá o saque.Contudo, quemchamouométodonãosaberáseosaque foi realizadoounão.Comonotificarqueminvocouométodoqueosaque foi feitocomsucessoounão?
UmaprimeirasoluçãoseriaalterarométodoSacapararetornarumbooleanoindicandoseosaque
foiounãoefetuado:
publicclassContaPoupanca:Conta{publicoverrideboolSaca(doublevalor){if(valor+0.10<=this.Saldo){this.Saldo-=valor+0.10;returntrue;}else{returnfalse;}}//Restodocódigodaclasse}
Assim,podemossaberseosaquefoiefetuadoaochamarométodo:
Contaconta=newContaPoupanca();//Inicializaacontaif(conta.Saca(100.0)){MessageBox.Show("Saqueefetuado");}
Essaabordageméimportante,porexemplo,nocasodeumcaixaeletrônico.Nósprecisamossaberseosaquefoiefetuadoounãoantesdeliberarmosodinheiroparaocliente.Contudo,umadesvantagemdessaabordageméque,seesquecermosdetestaroretornodométodoSaca,podemosliberardinheiro
paraoclientesempermissão.
Emesmoinvocandoométodoetratandooseuretornodemaneiraadequada,oquefaríamossefosse
EXCEÇÕES
16.1RETORNODOMÉTODOPARACONTROLARERROS
16EXCEÇÕES 125
necessáriosinalizarexatamentequalfoiotipodeerroqueaconteceu,comoquandoousuáriopassouumvalornegativocomoquantidade?
Umasoluçãoseriaalteraroretornodebooleanparanúmerointeiroeretornarocódigodoerroqueocorreu. Isso é considerado umamá prática, pois o valor devolvido é "mágico" e só legível peranteextensadocumentação(magicnumbers),alémdenãoobrigaroprogramadoratrataresseretorno,oquepodelevaroprogramaacontinuarexecutandoemumestadoinconsistente.
Umoutroproblemaaconteceriaseométodojáretornassealgumvalor.Dessejeito,nãodariaparaalteraroretornoparaindicarseosaquefoirealizadoounão.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
Para evitar esses problemas, o C# nos permite tratar essas exceções à regra de uma maneiradiferente:atravésdeexceptions.Emvezde retornarmosumvalor dizendo se umaoperação foi bemsucedida,nós lançamosumaexceçãoà regrapadrão, aocomportamentopadrão,dizendoquealgodeerradoaconteceu.Nonossocaso,utilizaremosaexceçãoException,indicandoquehouveumerrona
operaçãodesaque:
publicclassContaPoupanca:Conta{publicoverridevoidSaca(doublevalor){if(valor+0.10>this.Saldo){thrownewException("Valordosaquemaiorqueosaldo");}else{this.Saldo-=valor+0.10;}}}
VocêpodetambémfazerocursodatadessaapostilanaCaelum
16.2CONTROLANDOERROSCOMEXCEÇÕES
126 16.2CONTROLANDOERROSCOMEXCEÇÕES
Atéomomento,aprendemoscomolançarumaexceptionquandoalgumcomportamentoocorreudeforma fora do comum.Mas, o que essa exception influencia na classe que o chamou? Por exemplo,vamos ver o que acontece quando tentamos sacar umvalor superior ao saldo do cliente.Rode a suaaplicaçãocomF5etentesacarumvalorsuperioraosaldodeumcliente.
Aoclicarnobotãodesaque,aexecuçãodocódigoseráinterrompidanalinhaemqueaexceçãoélançada.IssoocorreporqueoF5rodaonossoprogramaemmododebug.SerodarmosoprogramaforadomododebugcomCtrl+F5,comosefosseumusuáriorodandooprograma,veríamosumajanela
dizendoqueocorreuumerro:
Mas, nós não queremos que o usuário receba talmensagemna tela.Então, não podemos chamardiretamenteummétodoquepodelançarumaexceção.Aoinvésdisso,devemostentarchamarométodo:senãoforlançadanenhumaexceção,ok;casocontrário,devemospegaraexceçãoeexecutarumtrechodecódigoreferenteàexceção.
Paratentarexecutarumtrechodecódigoquepodelançarumaexceção,devemoscolocá-lodentrodeumblocotry.Nonossocaso,colocaremosdentrodoblocoquetrataocliquedobotãosaque:
privatevoidbotaoSaque_Click(objectsender,EventArgse){intindice=comboContas.SelectedIndex;doublevalor=Convert.ToDouble(textoValor.Text);Contaselecionada=this.contas[indice];try{selecionada.Saca(valor);textoSaldo.Text=Convert.ToString(selecionada.Saldo);MessageBox.Show("DinheiroLiberado");}}
Eparapegaraexceçãocasosejalançadaetratá-la,devemospôrocódigodentrodeumblockcatch:
privatevoidbotaoSaque_Click(objectsender,EventArgse){intindice=comboContas.SelectedIndex;doublevalor=Convert.ToDouble(textoValor.Text);Contaselecionada=this.contas[indice];try{selecionada.Saca(valor);
16.2CONTROLANDOERROSCOMEXCEÇÕES 127
textoSaldo.Text=Convert.ToString(selecionada.Saldo);MessageBox.Show("DinheiroLiberado");}catch(Exceptionex){MessageBox.Show("Saldoinsuficiente");}}
Nessebloco,casoométodoSaca lanceumaexceção,oblococatchseráexecutadomostrandoa
mensagemSaldoInsuficiente.Nocasodeumaexceção,amensagemDinheiroLiberadonãoé
exibida.
Uma outra situação exceptional ocorre quando o usuário da classeConta tenta sacar um valor
negativo,claramenteumvalorinválidoparaosaque.Nessecasotambémqueremoslançarumaexceção:
publicoverridevoidSaca(doublevalor){if(valor<0.0){thrownewException();}if(valor+0.10>this.Saldo){thrownewException("Valordosaquemaiorqueosaldo");}else{this.Saldo-=valor+0.10;}}
QuandopassamosumvalornegativoparaométodoSaca, ométodo lançará umaException,
portantoo códigodoblococatch do caixa eletrônico será executadopara tratar a exceçãogerada,
exibindoparaousuárioamensagemSaldoInsuficiente. Porémessamensagemestá claramente
errada.
Repareque,parajogarmosaexceção,precisamosexecutarumnew,ouseja,aExceptionéuma
classedoC#!Podemoscriarumahierarquiadeexceçõesutilizandoaherançaparaindicarqualfoiotipodeerroqueocorreu.
Para criarmos um novo tipo de exceção, precisamos apenas criar uma nova classe que herde deException.Vamoscriarumaexceçãoqueindicaqueocorreuumerroporsaldoinsuficientenaconta,
aSaldoInsuficienteException:
publicclassSaldoInsuficienteException:Exception{}
16.3TRATANDOMÚLTIPLASEXCEÇÕES
128 16.3TRATANDOMÚLTIPLASEXCEÇÕES
EvamosutilizaroSaldoInsuficienteExceptionnométodoSacadaclasseContaPoupanca:
publicoverridevoidSaca(doublevalor){if(valor<0.0){thrownewException();}if(valor+0.10>this.Saldo){thrownewSaldoInsuficienteException();}else{this.Saldo-=valor+0.10;}}
Quandoousuáriopassaumargumentonegativo ainda lançamosuma exceçãogenérica.Podemoscriarumnovotipodeexceçãoqueindicaqueoargumentopassadoéinválido.Porém,oC#jápossuiumconjunto de exceções padrão na linguagem (http://msdn.microsoft.com/pt-br/library/system.exception.aspx#inheritanceContinued). Dentre essas exceções, existe aArgumentException, que indica que o argumento de um método é inválido. Vamos utilizar essa
exceçãononossocódigo:
publicoverridevoidSaca(doublevalor){if(valor<0.0){thrownewArgumentException();}if(valor+0.10>this.Saldo){thrownewSaldoInsuficienteException();}else{this.Saldo-=valor+0.10;}}
Agoraocódigodocaixaeletrônicopodetratardeformadiferentecadaumdostiposdeexceção:
privatevoidbotaoSaque_Click(objectsender,EventArgse){intindice=comboContas.SelectedIndex;doublevalor=Convert.ToDouble(textoValor.Text);Contaselecionada=this.contas[indice];try{selecionada.Saca(valor);textoSaldo.Text=Convert.ToString(selecionada.Saldo);MessageBox.Show("DinheiroLiberado");}catch(SaldoInsuficienteExceptionex){MessageBox.Show("Saldoinsuficiente");}
16.3TRATANDOMÚLTIPLASEXCEÇÕES 129
catch(ArgumentExceptionex){MessageBox.Show("Nãoépossívelsacarumvalornegativo");}}
Mas o que deve ser colocado dentro de um bloco try? Será que devemos colocar apenas a
execuçãodométodoquelançaaexceção?
privatevoidbotaoSaque_Click(objectsender,EventArgse){intindice=comboContas.SelectedIndex;doublevalor=Convert.ToDouble(textoValor.Text);Contaselecionada=this.contas[indice];try{selecionada.Saca(valor);}catch(SaldoInsuficienteExceptionex){MessageBox.Show("Saldoinsuficiente");}catch(ArgumentExceptionex){MessageBox.Show("Nãoépossívelsacarumvalornegativo");}textoSaldo.Text=Convert.ToString(selecionada.Saldo);MessageBox.Show("DinheiroLiberado");}
Ao executar o código, vemos que ométodo Saca lança a exceção de saldo insuficiente. Mas,
mesmoassim,ocaixaliberadinheiroparaousuário.IssoaconteceporqueaexceçãolançadanométodoSacajáfoitratadanosblocoscatcheaexecuçãodoprogramacontinuanormalmente.
Oblocotry deveconter todaa lógicadenegócioque será executadaemumasituaçãonormal,
quando não ocorrem casos excepcionais. Assim, podemos nos preocupar apenas com a lógica denegóciosedepoisnospreocupamoscomoserrosqueaconteceram.
Nocasodosaque,queremosexecutarométodoSacaedepoisemitirodinheirodentrodobloco
try.
privatevoidbotaoSaque_Click(objectsender,EventArgse){intindice=comboContas.SelectedIndex;doublevalor=Convert.ToDouble(textoValor.Text);Contaselecionada=this.contas[indice];try{selecionada.Saca(valor);textoSaldo.Text=Convert.ToString(selecionada.Saldo);MessageBox.Show("DinheiroLiberado");}catch(SaldoInsuficienteExceptionex){MessageBox.Show("Saldoinsuficiente");}catch(ArgumentExceptionex)
130 16.3TRATANDOMÚLTIPLASEXCEÇÕES
{MessageBox.Show("Nãoépossívelsacarumvalornegativo");}}
Vejaqueotratamentodoserrosficoutotalmenteisoladodalógicadenegócios.Utilizandoexceções,podemosnospreocuparapenascoma lógicadenegóciodosistemae sódepoiscomo tratamentodeerros.Nãoexistemisturadecódigo!
1. Quaisdasopçõesaseguirrepresentaolançamentodeumanovaexceçãoemnossosistema?
csharpthrownewException();
csharpreturnException();
csharpreturnnewException();
csharpthrowException();
2. Analiseocódigoaseguireassinaleaalternativacorreta:
varconta=newConta();varcaixa=newCaixa();conta.Deposita(100.0);conta.Saca(500.0);caixa.Libera(500.0);
Sealinha4lançarumaexceção,alinha5nãoseráexecutada.
Aúltimalinhanãoseráexecutadamesmoseocódigonãolançarexceções.
Sealinha4lançarumaexceção,nenhumadaslinhasseráexecutada.
Todasaslinhassãoexecutadasmesmoquandoalgumadelaslançaumaexceção.
3. Ondedevemoscolocarum trechodecódigoquepode lançarumaexceçãoparaquandoqueremostratá-la?
Dentrodeumblocotry
Dentrodeumblococatch
Nãoprecisaestaremnenhumblocoemespecífico.
4. Ondedevemoscolocarocódigoquetrataumaexceção?
Dentrodeumblococatch
16.4EXERCÍCIOS
16.4EXERCÍCIOS 131
Dentrodeumblocotry
Nãoprecisaestaremnenhumblocoemespecífico.
5. Modifique o método Deposita da classe ContaPoupanca para que ele lance um
ArgumentExceptionquandooargumentopassadoparaométodofornegativo.Oseumétododeve
ficarparecidocomoseguinte:
publicclassContaPoupanca:Conta{//restodocódigodaContaPoupancapublicoverridevoidDeposita(doublevalor){if(valor<0.0){thrownewArgumentException();}//restodométodocontinuaigual}}
Depoisdefazeressamodificação,executeaaplicaçãoetentedepositarumvalornegativoemumacontapoupançaevejaoqueacontece.
6. Agorautilizeumtry/catchnaaçãodobotãoquerealizaumdepósito,botaoDeposito_Clickda
classeForm1,paratrataraexceçãoquepodeserlançadapeloDeposita.QuandooDeposita
lançarumaexceção,mostreumMessageBoxcomamensagem"ArgumentoInválido".
7. (Opcional)VamosagoracriarumanovaexceçãochamadaSaldoInsuficienteExceptionqueserá
lançadatodavezquetentarmossacarumvalorqueésuperioraosaldoatualdaconta.EssaclassedevesimplesmenteherdardaclasseExceptiondoC#:
publicclassSaldoInsuficienteException:Exception{}
Agora modifique o método Saca da classe ContaPoupanca para que ele jogue a
SaldoInsuficienteExceptiontodavezqueousuáriotentarsacarumvalormaiordoqueosaldo
daconta.
Modifique também o método botaoSaque_Click para que ele mostre a mensagem "Saldo
Insuficiente"casoométodoSacalanceaexceçãoSaldoInsuficienteException.
8. (Opcional)FaçaasmesmasmodificaçõesparaaContaCorrente.
9. (Opcional) Um outro bloco que existe é o finally . Pesquise sobre ele em
http://msdn.microsoft.com/pt-br/library/fk6t46tz(v=vs.71).aspxedigaquandoumcódigodentrodeumblocofinallyéexecutado.
Sempre
132 16.4EXERCÍCIOS
Sóseumaexceçãoforlançada.
Nunca
Sósenenhumaexceçãoforlançada
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
16.4EXERCÍCIOS 133
CAPÍTULO17
Comocrescimentodosistema,passamosaterdiversasclassesnele.Porexemplo,asqueenvolvemomodelodenossosistemacomoasclassesligadasaconta:
publicabstractclassConta{//ImplementaçãodaclasseConta}
publicclassContaCorrente:Conta{//ImplementaçãodaclasseContaCorrente}
publicclassContaPoupanca:Conta{//ImplementaçãodaclasseContaPoupanca}
Asclassesvoltadasaorelacionamentocomocliente:
publicclassCliente{//ImplementaçãodaclasseCliente}
publicclassGerente{//ImplementaçãodaclasseGerente}
Asclassesligadasaosempréstimosfeitospelocliente:
publicclassCredito{//ImplementaçãodaclasseCredito}
publicclassCreditoImobiliario:Credito{//ImplementaçãodaclasseCreditoImobiliario}
Easclassesreferentesaosinvestimentos:
publicclassFundo{//ImplementaçãodaclasseFundo}
publicclassCDB
NAMESPACES
134 17NAMESPACES
{//ImplementaçãodaclasseCDB}
Ograndeproblemaquesurgecomossistemasgrandeséaorganizaçãodetodasassuasclasses.Paraevitar que o sistema fique caótico, podemos agrupar as classes por características comuns e dar umnome para cada um desses grupos. Isto é, agruparíamos um conjunto de classes em um espaço emcomum e lhe daríamos um nome, como por exemplo Caelum.Banco.Investimentos. Esse espaço
definidoporumnomeéchamadodenamespace.
Segundo a convenção de nomes adotada pela Microsoft (http://msdn.microsoft.com/en-us/library/893ke618.aspx), os namespaces devem ter a forma:NomeDaEmpresa.NomeDoProjeto.ModuloDoSistema.
Nonossocaso,osnamespacesficariamdaseguinteforma:
namespaceCaelum.Banco.Usuarios{publicclassCliente{//ImplementaçãodaclasseCliente}}
namespaceCaelum.Banco.Usuarios{publicclassGerente{//ImplementaçãodaclasseGerente}}
namespaceCaelum.Banco.Investimentos{publicclassFundo{//ImplementaçãodaclasseFundo}}
namespaceCaelum.Banco.Investimentos{publicclassCDB{//ImplementaçãodaclasseCDB}}
Antes de realizar essa separação de nossas classes em namespaces, elas estavam no mesmonamespace:onamespacedonomedoprojeto.Assim,paradefiniroclientereferenteauminvestimentoprecisaríamosapenascriarumnovoatributonaclasseInvestimento:privateClientecliente.
Contudo,comousodosnamespaces,aclasseCliente não estámais nomesmonamespaceda
classeInvestimento. Para poder referenciar qualquer uma das quatro classes anteriores devemos
indicaroseunamespace:
17NAMESPACES 135
Caelum.Banco.Usuarios.Gerenteguilherme=newCaelum.Banco.Usuarios.Gerente();Caelum.Banco.Usuarios.Clientemauricio=newCaelum.Banco.Usuarios.Cliente();Caelum.Banco.Investimentos.Fundoacoes=newCaelum.Banco.Investimentos.Fundo();Caelum.Banco.Investimentos.CDBcdb=newCaelum.Banco.Investimentos.CDB();
Onomecompletodeuma classe agora envolve adicionar uma referência aonamespacedela.Porisso, deixamos de acessar Gerente diretamente e passamos a acessar
Caelum.Banco.Usuarios.Gerente.
Umexemplodecódigo já existentenaplataformaC#queusanamespacesenvolve imprimirumaúnicalinhanoconsoleusandoométodoWriteLinedeSystem.Console:
System.Console.WriteLine("Minhacontabancaria");
Notecomoousodenamespacesparaorganizarsuasclassesacabaimplicandoemmaiscódigonahora de utilizar as mesmas. Por isso, podemos criar atalhos ao dizer que usaremos as classes quepertencemaumnamespace.Porexemplo,podemoscitarqueusaremosonamespaceSysteme,apartir
de então, podemos escrever nosso código como se tudo o que está dentro do namespace System
estivessenomesmonamespaceemqueestamos:
usingSystem;
Console.WriteLine("Minhacontabancaria");
Podemostambémusarváriosnamespacesdentrodomesmoarquivo:
usingSystem;usingCaelum.Banco.Usuarios;
Console.WriteLine("MinhaContaBancaria");Clientecliente=newCliente();
Autilizaçãodapalavrachaveusingpermitenotificaraocompiladorqueusaremosclassesdaquele
namespace. Com isso, obtemos a vantagem da organização do código através de namespace econtinuamoscomumcódigoenxuto.
NoC#,podemoscriarumnamespacedentrodeoutronamespacejáexistente.Porexemplo:
namespaceCaelum.Banco{//dentrodonamespaceCaelum.Banco
//agorapodemoscriarumnamespaceaninhadonamespaceContas{
17.1 PARA SABER MAIS - DECLARAÇÃO DE NAMESPACEANINHADOS
136 17.1PARASABERMAIS-DECLARAÇÃODENAMESPACEANINHADOS
//onomedessenamespaceéCaelum.Banco.Contas}}
OnamespaceContasdocódigoacimatambémpoderiaserdeclaradodaseguinteforma:
namespaceCaelum.Banco.Contas{//tambémdeclaraonamespaceCaelum.Banco.Contas}
ParaalinguagemC#,asduasdeclaraçõessãoequivalentes.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Emaplicaçõesgrandes,podemosternamespacescomnomesmuitograndes,porexemplo:
namespaceCaelum.Banco.Produtos.Contas{publicabstractclassConta{//Implementação}}
Vimos que, no códigoC#, podemos utilizar ousing para não digitarmos o nome completo da
classetodavezqueelaforutilizada,masoqueaconteceriasetivéssemosoutraclassechamadaConta?
Porexemplo,obancotemumsistemadeautenticaçãoeaclassequeguardainformaçõessobreousuárioéchamadaConta:
namespaceCaelum.Banco.Seguranca{publicclassConta{//Implementação}}
Agoraéamelhorhoradeaprenderalgonovo
17.2PARASABERMAIS-ALIASPARANAMESPACES
17.2PARASABERMAIS-ALIASPARANAMESPACES 137
Claramente, as classes são diferentes pois possuemnamespaces diferentes,mas no código que asutiliza,nãopodemosimportarasduasclassespoisocompiladordoC#nãosaberáqualdasduasestamosutilizando.
usingCaelum.Banco.Produtos.Contas;usingCaelum.Banco.Seguranca;
namespaceBanco.Sistema{publicclassControleAutenticacao{//ContadousuárioouContadobanco?publicvoidAutentica(Contaconta){//implementação}}}
Nessa situação, precisamos escolher qual é o namespace que vamos importar. Se colocarmos umusingparaCaelum.Banco.Produtos.Contas,porexemplo,parautilizarmosaConta dousuário
precisamos do nome completo da classe,Caelum.Banco.Seguranca.Conta, um nome bem grande.
Nessa situação, podemos dar um apelido (alias) menor para um namespace do C# com a palavrausing:
usingCaelum.Banco.Produtos.Contas;usingSegurancaDoBanco=Caelum.Banco.Seguranca;
namespaceBanco.Sistema{publicclassControleAutenticacao{//ContaéadonamespaceCaelum.Banco.Produtos.Conta//parausarmosacontadousuáriofazemos://SegurancaDoBanco.ContapublicvoidAutentica(SegurancaDoBanco.ContacontaUsuario){//implementação}}}
Podemostambémdefinirumaliasparaumaclassedonamespace:
usingCaelum.Banco.Produtos.Contas;usingContaDoUsuario=Caelum.Banco.Seguranca.Conta;
namespaceBanco.Sistema{publicclassControleAutenticacao{//ContaéadonamespaceCaelum.Banco.Produtos.Conta//parausarmosacontadousuário,utilizamosContaDoUsuariopublicvoidAutentica(ContaDoUsuarioconta){//implementação}}
138 17.2PARASABERMAIS-ALIASPARANAMESPACES
}
1. ComoinstanciaraclasseContaaseguir,queestádentrodeumnamespace?
namespaceCaelum.Banco{publicclassConta{//classeaqui}}
newConta();
newConta.Caelum.Banco();
newConta()inCaelum.Banco;
newCaelum.Banco.Conta();
2. Comoimportaraclasseaseguir,usandousing?
namespaceCaelum.Banco{publicabstractclassConta{//codigoaqui}}
usingCaelum;
usingCaelum.Banco;
usingCaelum.Banco.Conta;
3. FaçacomqueonamespacedascontasdaaplicaçãosejaBanco.Contas,porexemplo,paraaclasse
Conta,teríamos:
//arquivoConta.csnamespaceBanco.Contas{publicclassConta{//implementaçãodaclasseConta}}
Depoisde fazermosessamodificação,asclassesqueutilizamaconta terãoque importá-lacomousingdoC#.Noformulárioprincipaldaaplicação,classeForm1,porexemplo,teríamos:
usingBanco.Contas;
namespaceBanco{
17.3EXERCÍCIOS
17.3EXERCÍCIOS 139
publicclassForm1:Form{//implementaçãodoformulário}}
Repare que o namespace é completamente separado da estrutura de pastas do projeto, ou seja,podemosorganizarosarquivosdoprojetodaformaquedesejarmos.
4. (Opcional) Mesmo que a estrutura de diretórios seja completamente separada do namespace, ésemprebomdefinirmosregrasparaaestruturadepastasdoprojeto.Umaestruturamuitoutilizadano .Net é colocar todas as classes de um determinado namespace dentro de um diretório com omesmonomedonamespace.Paraascontasdaaplicação,porexemplo,teríamosaseguinteestrutura:
Vamosmoverosarquivosdoprojetoparaseguirmosessaestrutura.DentrodoprojetoBanco,crie
umanovapastachamadaContasedentrodessapastacoloquetodasascontasdosistema.Vejaque
podemosmoverlivrementeosarquivossemquebrarocódigodaaplicação.
140 17.3EXERCÍCIOS
CAPÍTULO18
Emcapítulosanterioresvimosautilizaçãodopolimorfismoparareferenciarmaisdeumtipodeclasse,comoéocasodasclassesContaCorrenteeContaPoupanca.Ambaspodemserreferenciadascomo
objetosdaclasseConta.
MasseráqueContaherdadealguém?Eseherdar,todasasoutrasclassestambémherdariam.Isto
é,umaclassequerepresentaabaseparatodososobjetosdosistema...umaclasseObject.Ocódigoa
seguiréomesmoqueadefiniçãoantigadeConta:
publicabstractclassConta:Object{//código}
ÉdesnecessáriodizermosqueContaherdadeObject.Écomoseoprópriocompiladorfizesseo
códigoanterioraodigitarmos:
publicabstractclassConta{//código}
Assim,podemosdizerque todaclasseemC#éumObject.UmavezqueConta éObject,
ContaCorrenteeContaPoupancapassamaserObjectindiretamente.
Vimos no primeiro capítulo sobre orientação a objetos que quando fazemos uma comparação deduasvariáveisdotipoConta,oquecomparamosnarealidadesãoasreferênciasqueestãoarmazenadas
nasvariáveis:
Contac1=newContaCorrente();c1.Numero=1;
Contac2=newContaCorrente();c2.Numero=1;
if(c1==c2){MessageBox.Show("iguais");}else
CLASSEOBJECT
18.1IMPLEMENTANDOACOMPARAÇÃODEOBJETOS
18CLASSEOBJECT 141
{MessageBox.Show("diferentes");}
Nessecódigo,asduascontascriadasguardamexatamenteasmesmasinformações,porémcomoc1
ec2guardamreferências,quandofazemosc1==c2,estamoscomparandoareferênciadavariável
c1comareferênciadavariávelc2e,comoelasapontamparaobjetosdiferentes,ocódigomostraa
mensagem"diferentes".
Paracorrigiresseproblema,precisamoscompararosvaloresdaspropriedadesdacontaaoinvésdovalor das variáveis c1 e c2 . Por exemplo, no sistema que desenvolvemos, duas contas são
consideradasiguaisapenasquandoseusnúmerossãoiguais,entãoocódigodacomparaçãodeveriaficardaseguinteforma:
if(c1.Numero==c2.Numero){MessageBox.Show("iguais");}else{MessageBox.Show("diferentes");}
Portanto,em todosospontosdosistemaemqueprecisamoscomparardoisobjetosdo tipoconta,precisamosrepetiroifacima.Masoqueaconteceriaseprecisássemosmudararegradecomparação
deduascontas?Nessecasoteríamosquebuscartodasascomparaçõesdecontasdaaplicaçãoeatualizararegra,oquepodesermuitotrabalhoso.
Pararesolveroproblemadacomparaçãodeobjetos,aMicrosoftintroduziunaclasseObject um
métodoespecializadoemfazeracomparaçãodedoisobjetos,ométodoEquals.Comoemtodaherançaa classe filha ganha os comportamentos da classe pai, podemos utilizar o Equals para fazer a
comparaçãoentredoisobjetos:
if(c1.Equals(c2)){MessageBox.Show("iguais");}else{MessageBox.Show("diferentes");}
Porém,aoexecutarmosocódigo,aaplicaçãoaindamostraamensagem"diferentes".Issoocorre
porqueaimplementaçãopadrãodoEqualsquevemherdadadaclasseObjectfazacomparaçãodas
referências,ouseja,oifdocódigoanterioraindafazacomparaçãoc1==c2.
PodemosmudarocomportamentopadrãodométodoEqualsherdadodaclasseObjectutilizando
asobrescrita:
publicabstractclassConta
142 18.1IMPLEMENTANDOACOMPARAÇÃODEOBJETOS
{//outraspropriedadesemétodos
//NessemétodoimplementamosaregradeigualdadeentreduascontaspublicoverrideboolEquals(Objectoutro){//Implementaçãodaigualdadedecontas.}}
ReparequeométodoEquals recebeumargumentodo tipoObject, entãopodemosutilizá-lo
paracompararumacontacomqualquervalordoC#.
Dentroda implementaçãodométodoEquals, queremos implementar a regra de igualdade entre
contas—duascontassãoiguaisseosseusnúmerosforemiguais:
publicabstractclassConta{//outraspropriedadesemétodos
//NessemétodoimplementamosaregradeigualdadeentreduascontaspublicoverrideboolEquals(Objectoutro){returnthis.Numero==outro.Numero;}}
Porém,reparequeavariáveloutroédotipoObject,quenãopossuiumapropriedadechamada
Numero,apenasaContapossuiessapropriedade.Então,antesdefazermosacomparaçãoprecisamos
converteravariáveloutroparaotipoContautilizandoocast:
publicabstractclassConta{//outraspropriedadesemétodos
//NessemétodoimplementamosaregradeigualdadeentreduascontaspublicoverrideboolEquals(Objectoutro){ContaoutraConta=(Conta)outro;returnthis.Numero==outraConta.Numero;}}
DepoisdecolocarmosessaimplementaçãodométodoEqualsnaclasseConta,podemostentar
executarnovamenteacomparaçãodecontas:
if(c1.Equals(c2)){MessageBox.Show("iguais");}else{MessageBox.Show("diferentes");}
Dessavez,oC#utilizaráa implementaçãodoEquals quecolocamosdentrodaclasseConta,
18.1IMPLEMENTANDOACOMPARAÇÃODEOBJETOS 143
fazendoacomparaçãopelosnúmeros.Portanto,teremosamensagem"iguais".
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
ReparequeométodoEqualsrecebeotipoObject.Sendoassim,podemoscompararacontacom
qualqueroutroobjetodosistema,porexemplo,astring:
Contac=newContaCorrente();
if(c.Equals("Mensagem"))
EnaimplementaçãodoEquals,fazemosocastdoargumentopassadoparaotipoConta,poréma
string não é uma conta. Como o cast é inválido, o C# lança uma exceção do tipo
InvalidCastException . Para evitarmos essa exceção precisamos verificar que o argumento do
Equalsé realmentedo tipoContaantesde fazermosaoperaçãodecast.Para fazeresse trabalho,
podemosutilizarooperadorisdoC#:
publicoverrideboolEquals(Objectoutro){if(outroisConta){//outroédotipoConta,entãopodemosfazerocast}}
Nessecódigo,seavariáveloutroguardarumareferênciaparaumobjetoqueédotipoConta
(instânciadeContaouclassefilha),oisdevolvetrue,senãoeledevolvefalse.
SeoutronãoforumaConta,entãoométododeveriadevolverfalse, do contrário ele deve
fazerocastecompararosnúmeros.Assim,oEqualspodeserimplementadocomoseguintecódigo:
publicoverrideboolEquals(Objectoutro){//SenãotemosumobjetodotipoConta
VocêpodetambémfazerocursodatadessaapostilanaCaelum
18.2MELHORANDOAIMPLEMENTAÇÃODOEQUALSCOMOIS
144 18.2MELHORANDOAIMPLEMENTAÇÃODOEQUALSCOMOIS
//Entãoométododevolvefalseif(!(outroisConta)){returnfalse}
ContaoutraConta=(Conta)outro;returnthis.Numero==outraConta.Numero;}
Nos capítulos anterioresmodificamos o formulário doBanco para utilizar um combo box para
fazeraorganizaçãodascontascadastradas.Paracolocarmosumnovoitemnocambobox,utilizamosométodoAddemsuapropriedadeItemspassandoqualéonovotextoquequeremosadicionar:
comboContas.Items.Add("NovoItem");
Com isso, o comboboxmostrará umnovo itemcomo texto"NovoItem".Naverdade, quando
utilizamosessemétodoAdd,podemospassarqualquerobjetocomoargumento:
Contac=newContaCorrente();c.Numero=1;
comboContas.Items.Add(c);
QuandopassamosumobjetoparaométodoAdd, oC#precisa transformar esse objeto emuma
stringqueseráexibidacomoitemdocombobox.Paraissoeleutilizamaisummétodoherdadoda
classeObjectchamadoToString.Aresponsabilidadedessemétodoétransformarumobjetoqualqueremumastring.
AimplementaçãopadrãodométodoToStringquevemherdadodaclasseObjectsimplesmente
devolveastringquerepresentaonomecompletodaclasse,ouseja,nomedonamespaceseguidodo
nomedaclasse(Banco.Contas.ContaCorrente,nocasodaContaCorrente).Mas,paramostrarmos
a conta no combo box, precisamos de uma implementação que descreva a conta que o usuário estáselecionando,entãovamosnovamenteutilizarasobrescritademétodosparamodificarocomportamentodoToString:
publicabstractclassConta{//outrosmétodosepropriedades
publicoverridestringToString(){
}}
DentrodessemétodoToString,precisamosdevolverumtextoquedescrevaacontaqueousuário
estáselecionando:
18.3INTEGRANDOOOBJECTCOMOCOMBOBOX
18.3INTEGRANDOOOBJECTCOMOCOMBOBOX 145
publicabstractclassConta{//outrosmétodosepropriedades
publicClienteTitular{get;set;}
publicoverridestringToString(){return"titular:"+this.Titular.Nome;}}
AgoraquecolocamosaimplementaçãodoToStringnaclasseConta,aoexecutarmosnovamente
o código que adiciona um item no combo box, o C# mostrará o resultado do ToString que foi
implementado.
1. Assinaleaalternativacorreta
TodasasclassesemC#herdamdiretamenteouindiretamentedeObject
Objectéumaclasseabstrata
SóasclassesquenãoherdamdenenhumaclassesãoherdadasdeObject
Objectéumainterface
2. Analiseocódigoaseguiredigaqualseráasuasaída.
classCliente{publicstringNome{get;set;}publicstringRg{get;set;}publicCliente(stringnome){this.Nome=nome;}publicoverrideboolEquals(Objectobj){ClienteoutroCliente=(Cliente)obj;returnthis.Nome==outroCliente.Nome&&this.Rg==outroCliente.Rg;}}
Clienteguilherme=newCliente("GuilhermeSilveira");guilherme.Rg="12345678-9";
Clientemauricio=newCliente("MauricioAniche");mauricio.Rg="12345678-9";
if(guilherme.Equals(mauricio)){MessageBox.Show("Sãoomesmocliente");}else
18.4EXERCÍCIOS
146 18.4EXERCÍCIOS
{MessageBox.Show("Nãosãoomesmocliente");}
Nãosãoomesmocliente
Ocódigonãocompila
Sãoomesmocliente
Nadaémostrado
Ocódigorodamasquebraaoexecutar
3. VamossobrescreverométodoToStringdaclasseContacomaseguinteimplementação:
publicabstractclassConta{//RestodaimplementaçãodaContapublicoverrideStringToString(){return"titular:"+this.Titular.Nome;}}
Agoraadicionaremosacontaaoinvésdeumastringcomoitemdocomboboxdentrodométodo
AdicionaContadoformulárioprincipaldaaplicação,classeForm1:
publicvoidAdicionaConta(Contaconta){this.contas[this.numeroDeContas]=conta;this.numeroDeContas++;comboContas.Items.Add(conta);}
Depoisdefazeressamodificação,testeaaplicaçãoevejaoToStringdacontaemaçãodentrodos
opçõesdocombobox.
4. Quandoadicionamosumobjetonocombobox,émais interessanterecuperardiretamenteoobjetoquefoiselecionadodoqueoíndicequefoiselecionado.
Para recuperar o objeto que está selecionado em um combo box, utilizamos a propriedadeSelectedItem.Essa propriedade devolve um Object que guarda a instância selecionada no
combobox.
Sabendodisso,podemosmodificaraaçãodobotãodedepósito,botaoDeposito_Clickdaclasse
Form1,parautilizaroSelectedItemdocomboContas,queconteráainstânciadacontaqueo
usuário selecionou na interface gráfica. Porém para podermos utilizar a conta selecionada,precisamosprimeiroconvertê-laparaumainstânciadeConta:
privatevoidbotaoDeposito_Click(objectsender,EventArgse){
18.4EXERCÍCIOS 147
Contaselecionada=(Conta)comboContas.SelectedItem;
//implementaalógicadedepósitoutilizandoaconta}
Implementeetesteessamodificaçãodentrodoseuprojeto.Façaomesmoparaobotãodesaque.
5. (Opcional)EmalgumassituaçõesnãoqueremosutilizaroToStringdopróprioobjetoparamontar
a listade itensdocombobox,nessassituações,podemosutilizarumapropriedadedoComboBox
chamadaDisplayMemberparaescolherqualéapropriedadedoobjetoquequeremosincluircomo
itemdocombo.Porexemplo,noseguintecódigo,ositemsdocomboboxserão1e2:
Contac=newContaCorrente(){Numero=1};Contac2=newContaCorrente(){Numero=2};comboContas.Items.Add(c);comboContas.Items.Add(c2);comboContas.DisplayMember="Numero";
QuandoutilizamosoDisplayMemberocomboboxtambémutilizaoToStringdomembropara
montaroitemqueseráexibidoparaousuário.
UtilizeoDisplayMemberparamostraroToStringdapropriedadeTitulardacontaaoinvésde
mostraroToStringdaprópriaConta.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
148 18.4EXERCÍCIOS
CAPÍTULO19
Sequisermosarmazenarmuitascontasnamemória,podemosfazerousodearrays,oqualjáestudamosnoscapítulosanteriores.Arraysnospossibilitamguardarumaquantidadedeelementosedepoisacessá-losdeformafácil.
Masoproblemaéquemanipularumarraynãoéfácil.Porexemplo,imagineumarraycom5contasguardadas. Se quisermos remover a posição 1, como fazemos? Pois, se apagarmos, precisaremosreordenartodonossoarray.Eparainserirumelementonomeiodoarray?Precisamos"abrirumburaco"noarray,empurrandoelementosprabaixo,paraaísimcolocaronovoelementonomeio.
Pararesolverosproblemasdoarray,podemostrabalharcomumaclassedoC#chamadaList.Para
utilizarmos uma lista dentro do código precisamos informar qual é o tipo de elemento que a listaarmazenará:
//criaumalistaquearmazenaotipoContaList<Conta>lista=newList<Conta>();
Damesma forma que criamos a lista de contas, também poderíamos criar uma lista de númerosinteirosoudequalqueroutrotipodoC#.EssalistadoC#armazenaseuselementosdentrodeumarray.
TRABALHANDOCOMLISTAS
19.1 FACILITANDO O TRABALHO COM COLEÇÕES ATRAVÉS DASLISTAS
19TRABALHANDOCOMLISTAS 149
AgoraqueinstanciamosoList,podemosutilizarométodoAddparaarmazenarnovoselementos:
Contac1=newContaCorrente();Contac2=newContaPoupanca();Contac3=newContaCorrente();
//c1ficanaposição0lista.Add(c1);//c2na1lista.Add(c2);//ec3na2lista.Add(c3);
SequisermospegaressaConta,podemosacessá-lapelasuaposição(nocaso,0,igualnoarray):
Contaconta=lista[0];
Sequisermosremoverumadascontasdalista,podemosusarométodoRemoveouRemoveAt:
//Alistacomeçadaseguinteforma:[c1,c2,c3]//DepoisdoRemove,elaterminadaseguinteforma:[c1,c3]//Acontac1continuanaposição0ec3vaiparaaposição1lista.Remove(c2);//removepeloelemento
//Depoisdessachamada,c3ocupaaposição0:[c3]lista.RemoveAt(0);//removepeloíndice
Se quisermos saber quantos elementos existem em nosso List, podemos simplesmente ler a
propriedadeCount:
varc1=newContaCorrente();varc2=newContaInvestimento();
lista.Add(c1);lista.Add(c2);
intqtdDeElementos=lista.Count;
Tambémpodemosdescobrirseumelementoestádentrodeumalista:
Contac1=newContaCorrente();Contac2=newContaPoupanca();
lista.Add(c1);
booltemC1=lista.Contains(c1);//truebooltemC2=lista.Contains(c2);//false
UmoutrorecursoqueaclasseListnosforneceéaiteraçãoemcadaumdosseuselementos:
Contac1=newContaCorrente();Contac2=newContaPoupanca();
lista.Add(c1);lista.Add(c2);
foreach(Contacinlista){MessageBox.Show(c.ToString());
150 19.1FACILITANDOOTRABALHOCOMCOLEÇÕESATRAVÉSDASLISTAS
}
VejacomolidarcomcoleçõesdeelementosficoumuitomaisfácilcomaclasseList!
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
1. ComodescobrimosaquantidadedeelementosarmazenadoemumList?
varlista=newList<Conta>();lista.Add(...);lista.Add(...);lista.Add(...);
lista.Size
lista.Count()
lista.Size()
lista.Count
lista.GetTotal()
2. Qualométodoqueremoveumelementodalistapelasuaposição?
lista.Remove(posicao);
lista.RemoveAt(posicao);
lista.DeleteFrom(posicao);
lista.DeleteAt(posicao);
Seuslivrosdetecnologiaparecemdoséculopassado?
19.2EXERCÍCIOS
19.2EXERCÍCIOS 151
3. AclasseListimplementaumainterfacemaisgenéricadelistas.Qualé?
Você pode consultar a documentação da classe no próprio site da Microsoft:http://msdn.microsoft.com/pt-br/library/6sh2ey19.aspx
IList
Nenhuma
List
GenericList
4. Vamosmodificarocódigodoprojetodobancoparautilizarlistasaoinvésdearraysparaguardarascontascadastradas.
Inicialmentesubstituaadeclaraçãodoatributoqueguardaareferênciaparaoarraydecontaspeladeclaraçãodeumalistadecontas.ApaguetambémadeclaraçãodoatributonumeroDeContas:
//Essadeclaraçãoseráutilizadanolugardoarray//decontasprivateList<Conta>contas;
ModifiqueométodoForm1_LoadparaqueeleinstancieumList<Conta>aoinvésdeumarrayde
contas:
privatevoidForm1_Load(objectsender,EventArgse){this.contas=newList<Conta>();
//orestodométodocontinuaigual}
Porfim,modificaremosométodoAdicionaContadoformulárioprincipal:
publicvoidAdicionaConta(Contaconta){this.contas.Add(conta);comboContas.Items.Add(conta);}
Depoisdessasmodificações,testeaaplicação.
152 19.2EXERCÍCIOS
CAPÍTULO20
Agora estamos interessados em melhorar o cadastro de contas que implementamos nos capítulosanteriores. O banco não quer aceitar o cadastro de contas cujo titular seja devedor, então dentro dosistemaprecisamosguardarumalistacomnomesdosdevedores:
List<string>devedores=newList<string>();
devedores.Add("victor");devedores.Add("osni");
Agoranocadastroprecisamosverificarseonomequefoidigitadonoformulárioestádentrodessalista.PodemosfazerissoutilizandoométodoContainsdaclasseList:
stringtitular=//lêocampotitulardocadastroboolehDevedor=devedores.Contains(titular);
MasaimplementaçãodoContainsdalistaprecisapercorrertodososnomescadastradosparasó
entãodevolverseoelementoestáounãodentrodalista.Dessaforma,dependendodotamanhodalista,essabuscapodeficardemorada.
Como vimos, as listas não são muito otimizadas para as operações de buscas, pois além depermitiremarepetiçãodeelementos(queprejudicaodesempenhodabusca),precisampercorrertodososelementosparaimplementaremaoperaçãoContains.
Quandoprecisamosqueaoperaçãodebuscasejarápida,utilizamososconjuntosdoC#aoinvésdaslistas.Conjuntossãoestruturasnasquaispodemosfazerbuscasrápidasequenãopermitemrepetiçãodeelementos.
UmdostiposdeconjuntosdisponíveisnoC#éaclasseHashSet.Parabuscardemaneirarápida,o
HashSet"categoriza"osseuselementos,deformaaencontrá-losrapidamente.Porexemplo,imagine
você em um supermercado. Se você quer comprar sorvete, você não olha todos os itens dosupermercado,massimvaidiretoparaaseçãodecongelados.Lá,vocêprocuraoseusorvetefavorito.Vejaquevocêolhoumuitomenoselementos,poisfoidiretoparaacategoriadele.OHashSet faz a
mesmacoisa.Eledá"categorias"paracadaumdoselementos,equandobuscaporeles,vaidiretoparaacategoria.
LIDANDOCOMCONJUNTOS
20.1OTIMIZANDOABUSCAATRAVÉSDECONJUNTOS
20LIDANDOCOMCONJUNTOS 153
AcategoriaédadaapartirdométodoGetHashCode()quevemherdadodaclasseObjectdoC#.
Essemétododevolveumnúmerointeiroquerepresentaqualéacategoriadoobjeto.
CUIDADOSAOSOBRESCREVEROGETHASHCODE
Quando sobrescrevemos o método Equals de uma classe é uma boa prática também
sobrescrevermos o método GetHashCode . Além disso, para que o HashSet funcione
corretamente,aimplementaçãodoGetHashCodedeveobedeceràseguinteregra:
Se tivermos dois objetos, objeto1 e objeto2 , com objeto1.Equals(objeto2)
devolvendoovalortrue,entãoosmétodosGetHashCodedoobjeto1edoobjeto2devem
devolveromesmovalor.Ouseja,objetosiguaisdevemserdamesmacategoria.
Umdetalheinteressantedosconjuntoséquevocêpodeadicionar,removereatémesmoverificarseum elemento está lá.Mas diferentemente da lista, você não consegue pegar um elemento randômiconela.Porexemplo,conjunto[10]nãofunciona!Eissofazsentido:nãoexisteordememumconjunto.
HashSet<string>devedores=newHashSet<string>();//PodemosadicionarelementosnoconjuntoutilizandoométodoAdddevedores.Add("victor");devedores.Add("osni");
//Parasabermosonúmerodeelementosadicionados,utilizamosapropriedade//Countdoconjunto.Nesseexemploelementosguardaráovalor2intelementos=devedores.Count;
//Oconjuntonãoguardaelementosrepetidos,entãosetentarmos//adicionarnovamenteastring"victor",onúmerodeelementos//continuasendo2devedores.Add("victor");
//Paraperguntarmosseoconjuntopossuiumdeterminadoelemento,//utilizamosométodoContains
154 20.1OTIMIZANDOABUSCAATRAVÉSDECONJUNTOS
boolcontem=devedores.Contains("osni");
//Nãopodemospegarumelementopelasuaposição,poisoselementosdo//conjuntonãopossuemumaordenaçãobemdeterminada.Ocódigoabaixo//geraumerrodecompilação:devedores[0];
ParaiterarmosnoselementosdeumHashSet,podemosutilizarnovamenteocomandoforeach:
foreach(stringdevedorindevedores){MessageBox.Show(devedor);}
QuandoexecutamosoforeachemumHashSet, aordememqueos elementos são iterados é
indefinida.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Emmuitasaplicaçõesalémdabuscarápida,tambémprecisamosmanteraordenaçãodoselementosde um conjunto. Nesse tipo de aplicação, podemos utilizar uma nova classe do C# chamadaSortedSet.
OSortedSet funciona de forma similar ao HashSet, utilizamos o Add para adicionar um
elemento, o Remove para remover itens, o Count para perguntar quantos elementos estão
armazenadoseContainsparaverificarseumdeterminadoelementoestánoconjunto.Adiferençaé
quenoHashSetoselementossãoespalhadosemcategoriaseporissonãosabemosqualéaordemda
iteração,jáoSortedSetguardaoselementosnaordemcrescente.Entãonoexemplodoconjuntode
devedores,teríamosumconjuntoemqueoselementosestãoemordemalfabética:
SortedSet<string>devedores=newSortedSet<string>();
devedores.Add("Hugo");devedores.Add("Ettore");devedores.Add("Osni");
Agoraéamelhorhoradeaprenderalgonovo
20.2CONJUNTOSORDENADOSCOMOSORTEDSET
20.2CONJUNTOSORDENADOSCOMOSORTEDSET 155
devedores.Add("Alberto");devedores.Add("Victor");
//Esseforeachvaimostrarosnomesnaseguinteordem://Alberto,Ettore,Hugo,OsnieporfimVictorforeach(stringnomeindevedores){MessageBox.Show(nome);}
VimosquetemosduasclassesquerepresentamconjuntosnoC#,oHashSeteoSortedSet,em
ambasasclasses,quandoqueremosarmazenarumelementoutilizamosométodoAdd,pararemovero
Remove,parabuscaroContainseparasaberonúmerodeelementosoCount, por essemotivo,
existe uma interface que declara todos os comportamentos comuns aos conjunto que é a interfaceISet.
Vimosqueaslistaseosconjuntossãoduasestruturasqueexpõemmuitosmétodosemcomum,masquetambémpossuemdiversasdiferenças:
Naslistasoselementossãoarmazenadosnaordemdeinserçãoenquantocadaconjuntoarmazenaoselementosnaordemquedesejarparaotimizarotempodebusca;Listasaceitamrepetiçõesenquantoosconjuntosnão;Podemosacessarelementosdeumalistaatravésdeseuíndice,umaoperaçãoquenãofazsentidonoconjunto..
Comolistaseconjuntospossuemmuitasoperaçõesemcomum,tantoaslistasquantoosconjuntosimplementamumaoutrainterfacedoC#chamadaICollection:
20.3AINTERFACEDETODOSOSCONJUNTOS
20.4COMPARAÇÃOENTRELISTASECONJUNTOS
156 20.3AINTERFACEDETODOSOSCONJUNTOS
Além disso, aprendemos que podemos utilizar o foreach com qualquer coleção do C#. Isso
aconteceporqueoforeachaceitaqualquerclassequeimplementeainterfaceIEnumerable, que é
umasuperinterface(interfacepai)daICollection:
20.4COMPARAÇÃOENTRELISTASECONJUNTOS 157
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
1. Qualasaídadoprogramaaseguir?
varconjunto=newHashSet<Conta>();varc1=newContaCorrente();conjunto.Add(c1);conjunto.Add(c1);MessageBox.Show(conjunto.Count.ToString());
0
1
UmSetnãopossuipropriedadeCount
2
2. Comoeliminartodososelementosdeumconjunto?
varconjunto=newHashSet<Conta>();conjunto.????();
.Clear()
.DeleteAll()
.Reset()
.Empty()
3. No Banco, não podemos criar novas contas para clientes que são devedores, então na tela decadastrodenovaconta,antesdecriarmosanovacontaqueseráadicionadanaaplicaçãoprecisamosverificarseelaestáemumalistadedevedoresquecontém30000nomes.
EditoraCasadoCódigocomlivrosdeumaformadiferente
20.5EXERCÍCIOS
158 20.4COMPARAÇÃOENTRELISTASECONJUNTOS
Adicionenoprojetoumanovapasta chamadaBusca e dentrodessapasta crie umanova classe
chamadaGeradorDeDevedorescomoseguintecódigo:
namespaceBanco.Busca{publicclassGeradorDeDevedores{publicList<string>GeraList(){List<string>nomes=newList<string>();for(inti=0;i<30000;i++){nomes.Add("devedor"+i);}returnnomes;}}}
Essaéaclassequeseráresponsávelporgeraralistadedevedoresqueutilizaremosnaaplicação.
No construtor do formulário de cadastro, classe FormCadastroConta , vamos utilizar o
GeradorDeDevedoresparainicializaralistadedevedores:
publicpartialclassFormCadastroConta:Form{privateICollection<string>devedores;
privateForm1formPrincipal;
publicFormCadastroConta(Form1formPrincipal){this.formPrincipal=formPrincipal;InitializeComponent();
GeradorDeDevedoresgerador=newGeradorDeDevedores();this.devedores=gerador.GeraList();}
//Restodaclassecontinuaigual}
Agoranaaçãodobotãodecadastro,antesdecriarmosaconta,precisamosverificarseotitulardessanovacontaédevedor:
privatevoidbotaoCadastro_Click(objectsender,EventArgse){stringtitular=textoTitular.Text;boolehDevedor=this.devedores.Contains(titular);if(!ehDevedor){//fazalógicaparacriaraconta}else{MessageBox.Show("devedor");}}
20.4COMPARAÇÃOENTRELISTASECONJUNTOS 159
4. Paraverificarmosadiferençaentreo tempodebuscade listaseconjuntos,vamos repetirabusca30000vezesdentrodeumloop:
privatevoidbotaoCadastro_Click(objectsender,EventArgse){stringtitular=this.textoTitular.Text;boolehDevedor=false;for(inti=0;i<30000;i++){ehDevedor=this.devedores.Contains(titular);}if(!ehDevedor){//fazalógicaparacriaraconta}else{MessageBox.Show("devedor");}}
Enquantoocódigoestáexecutando,tentemoverajanela.Oqueaconteceu?
5. AgoramodifiqueoGeradorDeDevedoresparaqueeleutilizeumHashSetaoinvésdeumList:
publicHashSet<string>GeraList(){HashSet<string>nomes=newHashSet<string>();for(inti=0;i<30000;i++){nomes.Add("devedor"+i);}returnnomes;}
Repare que, para utilizarmos o HashSet, precisamos mudar os tipos do objeto instanciado, da
variável e do retorno no método. O que podemos fazer para evitar tantas mudanças quandoqueremostrocaraimplementaçãodecoleçãoqueusamos?
6. Testenovamenteocadastrodacontaevejaquedessavezabuscaémaisrápida.7. ExperimentetambémoutrascoleçõesnométodoGeraList.
Noprojetodobanco,temosdiversascontascadastradaseagoraqueremoscriarumanovabuscadecontapornomedotitular.Paraimplementaressabusca,podemositerarnalistadecontasecompararonomedotitulardecadaumadessascontas:
IList<Conta>contas=//pegaascontascadastradasstringtitularDaBusca="victor";Contaresultado=null;foreach(Contacontaincontas){if(conta.Titular.Nome.Equals(titularDaBusca))
20.6BUSCASRÁPIDASUTILIZANDODICIONÁRIOS
160 20.6BUSCASRÁPIDASUTILIZANDODICIONÁRIOS
{resultado=conta;break;}}
Agora repare que em todo ponto do código em que precisamos buscar uma conta pelo nome dotitular, precisamos repetir esse bloco de código, além disso, essa busca passa por todas as contascadastradasnosistema,oquepodedemorarbastante.Pararesolveresseproblemadeformaeficiente,oC#nosofereceosDicionários(Dictionary).
ODictionaryéumaclassequeconsegueassociarumachaveaumvalor.Utilizandoodicionário,
podemos,porexemplo,associaronomedotitularcomumacontadosistema.Quandovamosconstruirumdicionáriodentrodocódigo,precisamosinformarqualéotipodachaveequalseráotipodovalorassociadoa essa chave,para implementarmosabuscade contas, precisaríamosdeumdicionárioqueassociaumachavedotipostringcomumaConta.
Dictionary<String,Conta>dicionario=newDictionary<String,Conta>();
Agoraparacolocarmosumvalornodicionário,utilizamosométodoAdd:
Dictionary<String,Conta>dicionario=newDictionary<String,Conta>();Contaconta=//inicializaaconta
//vamosadicionaracontanodicionário//associaonomedotitularcomaconta.dicionario.Add(conta.Titular.Nome,conta);
Depoisqueinicializamosodicionário,podemosrealizarbuscasdevaloresutilizandoaschavesqueforamcadastradas.Vamos,porexemplo,buscaracontadeumtitularchamado"Victor":
Contabusca=dicionario["Victor"];
Veja que utilizando dicionários a busca por nomes ficou muito mais simples do que a buscautilizandooforeach,alémdisso,asbuscascomdicionáriossãotãorápidasquantobuscasutilizando
conjuntos,ouseja,muitomaiseficientesdoqueonossoforeachinicial.
Alémde fazermosbuscas rápidas, podemos também iterarnos elementosque estão armazenados,para isso tambémutilizamosoforeach doC#. Porémqual será o tipo que utilizaremos dentro do
foreach?
Ao iterarmos em um dicionário, o tipo utilizado dentro do foreach é um tipo que consegue
guardarumparde chaveassociadoaumvalordodicionário (KeyValuePair).Logo, no códigodo
foreachotiposeriaKeyValuePair<tipodachave,tipodovalor>:
Dictionary<string,Conta>dicionario=newDictionary<string,Conta>();
20.7ITERANDONODICIONÁRIO
20.7ITERANDONODICIONÁRIO 161
//preencheodicionário
foreach(KeyValuePair<string,Conta>parindicionario){//podemosacessarachaveatualdodicionáriostringchave=par.Key;
//epodemospegarovalorassociadoàchaveContavalor=par.Value;}
Assim como no HashSet, quando iteramos em um dicionário, seus elementos não estão em
nenhuma ordem em particular, logo não podemos depender da ordem dos elementos do dicionário.Quando estamos trabalhando com um algoritmo que depende da ordem dos elementos, precisamosutilizarumoutro tipodedicionáriochamadoSortedDictionary.OusodoSortedDictionary é
igual ao do Dictionary, porém seus elementos estão sempre na ordem crescente das chaves do
dicionário.
No C#, temos uma interface implementada por todos os tipos os tipos de dicionários, aIDictionary, além disso, os dicionários também implementam a interface ICollection do C#,
porémelessãocoleçõesdeKeyValuePair.Podemosversuahierarquianaimagemaseguir:
AhierarquiadascoleçõesdoC#ficadaseguinteforma:
162 20.7ITERANDONODICIONÁRIO
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Em nosso banco, precisamos implementar uma nova busca de contas por nome do titular. Paraimplementarmosessabusca,utilizaremososdicionáriosdoC#.
Noformulárioprincipaldaaplicação,coloqueumnovocampodetextoquereceberáqualéonomedotitulardabusca.ChameessecampodetextoBuscaTitular.Alémdessenovocampodetexto,
coloquetambémumnovobotãoquequandoclicadoexecutaráabuscapornome,chameessebotãodebotaoBusca.Oseuformuláriodeveficarparecidocomoquesegue:
JáconheceoscursosonlineAlura?
20.8EXERCÍCIOS
20.5EXERCÍCIOS 163
Paraimplementarmosessabuscapornomedetitular,oformulárioprecisadeumnovoatributodotipoDictionary.Quaisdevemserostiposdachaveedovalordodicionário?Agoraquetemoso
dicionário,todavezquecriamosumanovaconta,precisamosadicioná-laàlistadecontas,nocomboboxenodicionáriodecontas,mascomooformuláriopossuiummétodoespecializadoemadicionarnovascontas,oAdicionaConta,sóprecisamosmodificaraimplementaçãodessemétodo.Repare
quecomoocódigoestáencapsulado,precisamosapenasmodificaressemétodoquetudofuncionaráautomaticamente.
publicpartialclassForm1:Form{privateDictionary<string,Conta>dicionario;
privatevoidForm1_Load(objectsender,EventArgse){this.dicionario=newDictionary<string,Conta>();
//restodométodo}
publicvoidAdicionaConta(Contaconta){contas.Add(conta);comboContas.Items.Add(conta);
//agorasóprecisamosatualizarodicionáriothis.dicionario.Add(conta.Titular.Nome,conta);}
//Restodocódigodaclasse}
Agora que já preparamos o dicionário, precisamos apenas utilizá-lo para implementar a ação dobotãodebuscaportitular.
164 20.8EXERCÍCIOS
privatevoidbotaoBusca_Click(objectsender,EventArgse){//Precisamosprimeirobuscarqualéonomedotitularquefoidigitado//nocampodetextostringnomeTitular=textoBuscaTitular.Text;
//Agoravamosusarodicionárioparafazerabusca.//ReparecomoocódigodebuscaficasimplesContaconta=dicionario[nomeTitular];
//EagorasóprecisamosmostraracontaquefoiencontradanabuscatextoTitular.Text=conta.Titular.Nome;textoNumero.Text=Convert.ToString(conta.Numero);textoSaldo.Text=Convert.ToString(conta.Saldo);}
2. (Opcional)Nocódigodoexercíciopassado,quandoencontramosumacontadentrododicionário,estamos apenas atualizando as informações que são mostradas nos campos textoNumero ,
textoSaldoetextoTitular,porémquandotentamosfazerumaoperação,sempreutilizamoso
itemqueestáselecionadoatualmentenocomboContas.Precisamosutilizaracontadevolvidapelo
dicionárioparaatualizarovalorselecionadodocomboContas,parafazerisso,precisamosapenas
atribuiracontaquequeremosselecionarnapropriedadeSelectedIndexdocomboContas:
privatevoidbotaoBusca_Click(objectsender,EventArgse){stringnomeTitular=textoBuscaTitular.Text;Contaconta=dicionario[nomeTitular];
//AgoravamosatualizaroitemselecionadodocomboContas:comboContas.SelectedItem=conta;}
QuandoescrevemosnapropriedadeSelectedItem,oWindowsFormsautomaticamentechamaa
açãodemudançade itemselecionadodocombobox(ocomboContas_SelectedIndexChanged),
logonãoprecisamosnospreocuparematualizaroscamposdetextonocódigodabuscapornomedotitular.
3. O que acontece quando tentamos buscar um nome de titular que não existe? Tente modificar ocódigodoformulárioparacorrigiroproblema.
20.8EXERCÍCIOS 165
CAPÍTULO21
Nossobancoarmazenaumalistadecontas.Essascontaspossuemosmaisvariadoscorrentistas,saldosetipos.Muitasvezes,precisamosfiltrá-lasdealgumaforma.Porexemplo,sequisermospegar todasascontascomsaldomaiorque2000reais,fazemos:
varlista=newList<Conta>();
//inserimosalgumascontaslista.Add(...);
//crialistaqueusaremosparaguardaroselementosfiltradosvarfiltrados=newList<Conta>();foreach(varc:lista){if(c.Saldo>2000){filtrados.Add(c);}}
//agoraavariavel"filtrados"temascontasquequeremos!
Secomplicarmosaindamaisofiltro(porexemplo,contascomsaldomaiorque2000emenorque5000,comdatadeaberturaentreosanos2010e2012,...),nossocódigoficarátambémmaiscomplexo,alémdisso,sequiséssemosaplicarumfiltroemumalistacomoutrotipodeobjeto,teríamosquerepetirnovamenteocódigodoforeachemdiversospontosdaaplicação.
Parafiltrarumalista,seriamuitomaisinteressantequeaprópriacoleçãotivessealgummétodoquerecebesseacondiçãoquequeremosaplicarnessefiltroejáimplementassealógicadoforeach,algo
como:
List<Conta>contas=//inicializaalista
varfiltradas=contas.Filtra(condição);
Mascomopassaracondiçãoparaessefiltro?Teríamosqueenviarumblocodecódigoqueaceitaourejeitaosvaloresdacoleção.Parapassarumblocodecódigoquepodeserutilizadoporummétodo,oC# introduziu as funções anônimas ou lambdas. As funções anônimas funcionam como métodosestáticosdalinguagemcomumadeclaraçãosimplificada.Paradeclararumafunçãoanônimaquerecebe
LINQELAMBDA
21.1FILTROSUTILIZANDOOLINQ
166 21LINQELAMBDA
umargumentodotipoContautilizamososeguintecódigo:
(Contac)=>{//implementaçãodafunçãoanônima}
Dentrodoblocodeimplementaçãodafunçãoanônima,colocaremosaimplementaçãodacondição:
(Contac)=>{returnc.Saldo>2000;}
EagoraessafunçãopodeserpassadaparadentrodométodoFiltra:
contas.Filtra((Contac)=>{returnc.Saldo>2000;});
NoC#temosexatamenteaimplementaçãodessaideia,masométodosechamaWhereaoinvésde
Filtra.Então,parabuscarmostodasascontasquetêmumsaldomaiordoque2000,utilizaríamoso
seguintecódigo:
List<Conta>contas=//inicializaalistavarfiltradas=contas.Where((Contac)=>{returnc.Saldo>2000;});
Agoraquetemosalistadecontasfiltradas,podemos,porexemplo,iterarnessalista:
foreach(Contacontainfiltradas){MessageBox.Show(conta.Titular.Nome);}
AbibliotecadoC#quedefineométodoWhereéchamadaLINQ,aLanguageIntegratedQuery.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
Veja que, no código do lambda que passamos como argumento para oWhere, definimosqueo
argumentodafunçãoanônimaédotipoContaporquealistadavariávelcontasédotipoConta.
Reparequeotipodoargumentodolambdanaverdadeéredundanteeporisso,desnecessário:
varfiltradas=contas.Where(c=>{returnc.Saldo>2000;});
VocêpodetambémfazerocursodatadessaapostilanaCaelum
21.2SIMPLIFICANDOADECLARAÇÃODOLAMBDA
21.2SIMPLIFICANDOADECLARAÇÃODOLAMBDA 167
Alémdisso, quandodeclaramosuma função anônimaque temapenasuma linhaquedevolveumvalor,podemosremoverinclusiveaschaveseoreturndadeclaraçãodolambda:
varfiltradas=contas.Where(c=>c.Saldo>2000);
Vejaqueessecódigofinalémuitomaissimplesdoqueadeclaraçãoinicialqueutilizamosparaafunçãoanônima.
Agoraimaginequequeremossaberqualéasomadosaldodetodasascontasqueestãocadastradasdentro da aplicação. Para resolver esse problema, teríamos que fazer um código parecido com oseguinte:
List<Conta>contas=//inicializaalistadecontasdoubletotal=0.0;
foreach(Contacincontas){total+=c.Saldo;}
Porém esse tipo de código também acaba ficando repetitivo.Quando queremos fazer a soma doselementosdeumalista,podemosutilizarométodoSumdoLINQ,passandoumlambdaquefalaqualéapropriedadedacontaquequeremossomar:
doubletotal=contas.Sum(c=>c.Saldo);
Com essa linha de código conseguimos omesmo efeito do foreach anterior. Além do Sum,
tambémpodemosutilizar ométodoAverage para calcular amédia dosvalores,Count para contar onúmerodevaloresqueobedecemalgumcritério,MinparacalcularomenorvaloreMaxparacalcularomaiorvalor:
List<Conta>contas=//inicializaalista
//somadossaldosdetodasascontasdoublesaldoTotal=contas.Sum(c=>c.Saldo);
//mediadosaldodascontasdoublemediaDosSaldos=contas.Average(c=>c.Saldo);
//númerodecontasquepossuemNumeromenordoque1000intnumero=contas.Count(c=>c.Numero<1000);
intmenorNumero=contas.Min(c=>c.Numero);
doublemaiorSaldo=contas.Max(c=>c.Saldo);
Quandoutilizamosessesmétodosdeagregaçãoemumalistacomtiposprimitivos,olambdaéumargumentoopcional.Porexemplo,setivéssemosumalistadedouble,poderíamosutilizaroseguinte
códigoparacalcularamédiadosnúmeros:
21.3OUTROSMÉTODOSDOLINQ
168 21.3OUTROSMÉTODOSDOLINQ
List<double>saldos=//inicializaalista
doublemedia=saldos.Average();
OLINQ, alémde trabalhar com listas, tambémpode serutilizados comoutros tiposde coleções,podemosutilizaroLINQcomqualquerobjetoqueimplementeainterfaceIEnumerable,ouseja,ele
podeserutilizadocomqualquerobjetoquepossaserpassadoparaa instruçãoforeach. Isso inclui
todosostiposdecoleções(Listas,conjuntosedicionários)earrays.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
VimosqueutilizandooLINQpodemosfazerfiltroseagregaçõesdeumaformafácilemqualquercoleçãodoC#,porémquandoprecisamosfazerumfiltrocomplexo,olambdapodeficarcomumcódigocomplexo.Eporisso,aMicrosoftdecidiufacilitaraindamaisousodoLINQ.
Para implementarmos um filtro, em vez de utilizarmos ométodoWhere, podemos utilizar uma
sintaxequefoibaseadanalinguagemdebuscaembancodedados,aSQL.Paracomeçarmosumfiltroutilizandoessanovasintaxe,precisamoscomeçarofiltrocomapalavrafromcriandoumavariávelqueseráutilizadaparanavegarnalista:
varfiltradas=fromcincontas
Agora para colocarmos uma condição nesse filtro, utilizamos a palavrawhere passando qual é acondiçãoaqueacontadeveobedecerparaaparecercomoresultadodessefiltro:
varfiltradas=fromcincontaswherec.Numero<2000
21.4UTILIZANDOOLINQCOMOUTROSTIPOS
Seuslivrosdetecnologiaparecemdoséculopassado?
21.5 MELHORANDO AS BUSCAS UTILIZANDO A SINTAXE DEQUERIES
21.4UTILIZANDOOLINQCOMOUTROSTIPOS 169
Eporfim,precisamosapenasinformaroqueseráselecionadoutilizandooselect:
varfiltradas=fromcincontaswherec.Numero<2000selectc;
Com esse código, estamos definindo um filtro que devolverá apenas as contas que têm númeromenordoque2000.
Quandoocompiladorda linguagemC#encontrao filtroquedefinimos, essecódigoé convertidoparaumachamadaparaométodoWherequevimosanteriormente.Essanovasintaxeéapenasumjeito
deesconderacomplexidadedolambda.
Muitasvezes,quandoestamosusandooLINQ,ofiltronãoprecisaretornartodasasinformaçõesdosobjetosdalistaqueestásendoprocessada.Podemosestarinteressadosembuscarapenasonúmerodascontasqueobedecemoscritériosdabusca,paraissoprecisamosapenasmudaroselectdoLINQ.
List<Conta>contas=//inicializaalista
varresultado=fromcincontaswhere<condiçãodabusca>selectc.Numero;
Oresultadodessabuscaseráumacoleçãodenúmerosinteiros.
Mas e quando queremos devolver mais atributos da conta? Como no LINQ podemos apenasdevolverumobjetocomoresultadodaquery,teríamosquecriarumaclassequecontémosatributosqueserãodevolvidospelaquery,masmuitasvezesnósfazemosabuscaeutilizamosoresultadodentrodeum único ponto da aplicação (dentro de ummétodo, por exemplo).Nesses casos, podemos deixar ocompiladordoC#cuidardacriaçãodesseobjetoanônimo:
varresultado=fromcincontaswhere<condiçãodabusca>selectnew{c.Numero,c.Titular};
Nessecódigo,ocompiladordoC#criaumnovotipoqueseráutilizadoparaguardaroresultadodabusca.Esse tipo não possui umnomedentro do código e por isso o objeto devolvido é chamado deObjetoAnônimo.QuandoutilizamosoobjetoanônimonoLINQ,somosforçadosautilizarainferênciadetipos(palavravar).
No exemplo, o objeto anônimo devolvido pelo compilador possui as propriedades Titular e
Numero,portantopodemosutilizá-lasdentrodeumforeach:
foreach(varcinfiltradas){//aquidentropodemosapenasusaroTitulareoNumero,//setentarmosacessaroSaldoteremosumerrodecompilaçãoMessageBox.Show(c.Titular.Nome+""+c.Numero);}
21.6PARASABERMAIS—PROJEÇÕESEOBJETOSANÔNIMOS
170 21.6PARASABERMAIS—PROJEÇÕESEOBJETOSANÔNIMOS
1. CrieumnovoformuláriochamadoFormRelatorios.Utilizá-lo-emosparamostraroresultadode
queriesfeitasutilizandooLINQ.
No editor gráfico desse novo formulário, abra a janela Toolbox e adicione o componente
ListBox,chame-odelistaResultado.UtilizaremosesseListBoxparamostrarosresultados
devolvidospeloLINQ.
Agora vamos criar nosso primeiro relatório, o de busca de contas com saldomaior do que 5000,atravésdeumnovobotãodentrodajanela.UtilizeonomebotaoFiltroSaldo:
Quandoessebotãoforclicado,queremosexecutarumfiltrocomoLINQ:
privatevoidbotaoFiltroSaldo_Click(objectsender,EventArgse){//Aquiimplementaremosofiltro}
Comoosrelatóriosprecisarãodalistadecontas,pediremosessalistanoconstrutordajanela:
publicpartialclassFormRelatorios:Form{privateList<Conta>contas;publicFormRelatorios(List<Conta>contas){InitializeComponent();this.contas=contas;}//outrosmétodosdajanela.}
Dentrodaaçãodobotão,implementeabuscaportodasascontasquepossuemsaldomaiordoque5000.AgorautilizaremosoListBoxparamostrarascontasdevolvidaspeloLINQ.
OListBoxfuncionacomooComboBox.Quandoqueremosadicionarumanovalinha,precisamos
adicionaroobjetoquequeremosmostrardentrodapropriedadeItemsdoListBox.Elemostrará
21.7EXERCÍCIOS
21.7EXERCÍCIOS 171
o ToString() do objeto adicionado. Como utilizaremos esse ListBox para mostrarmos o
resultadodediversasbuscas,precisamoslimparoresultadoanteriorantesdemostraropróximo,efazemosissoatravésdométodoClear()dapropriedadeItems:
privatevoidbotaoFiltroSaldo_Click(objectsender,EventArgse){listaResultado.Items.Clear();varresultado=//querydoLINQforeach(varcinresultado){listaResultado.Items.Add(c);}}
Agorapara testarmosessabusca,vamosadicionarumnovobotãodentrodo formulárioprincipal,classe Form1 , chamado botaoRelatorio que instanciará o formulário FormRelatorios
passandoalistadecontascomoargumentoedepoischamaráoShowDialogparamostraressanova
janela:
privatevoidbotaoRelatorio_Click(objectsender,EventArgse){FormRelatoriosform=newFormRelatorios(this.contas);form.ShowDialog();}
2. Agora vamos implementar um novo relatório com o LINQ. Dessa vez, queremos listar todas ascontas antigas (numeromenordoque10) com saldomaior doque1000.Para isso crie umnovobotãona janela de relatórios quequando clicado executará a querydoLINQna lista de contas emostraoresultadodentrodoListBoxquecriamosnoexercícioanterior.
3. Agoravamoscolocar resumosdas informaçõescontidasno relatório.Para isso,colocardentrodo
172 21.7EXERCÍCIOS
relatórioumnovoGroupBoxqueteráotítuloResumo.DentrodesseGroupBox,mostraremos,por
exemplo,qualéosaldodacontademaiorSaldoequaléoSaldototaldetodasascontas.
Além desse GroupBox, coloque algumas 4 labels para mostrar os resumos desse relatório. O
primeirodevemostraro textoSaldoTotal, o segundo, o textoMaiorSaldo.Osdois labels
restantesserãoutilizadosparamostrarosresumos—chameoterceirolabeldelabelSaldoTotale
oúltimodelabelMaiorSaldo.Seuformuláriodeveficarparecidocomafiguraaseguir:
Depoisdemodificarmoso formulário,vamosmodificarasaçõesdobotãoparaqueelas, alémdefazerema busca, também atualizem o resumo com as informações da busca. Podemos extrair osresumosdaseguinteforma:
privatevoidbotaoFiltroSaldo_Click(objectsender,EventArgse){listaResultado.Items.Clear();varresultado=//querydoLINQforeach(varcinresultado){listaResultado.Items.Add(c);}doublesaldoTotal=resultado.Sum(conta=>conta.Saldo);doublemaiorSaldo=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 informações para oresumodorelatório.
21.7EXERCÍCIOS 173
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Alémdefazermosbuscaseprojeções,podemostambémutilizaroLINQparaordenarcoleçõesdeelementos. Para isso precisamos apenas colocar um orderby dentro da query. Por exemplo, parabuscarmostodasascontascomsaldomaiordoque10000ordenadaspelonomedotitular,utilizamososeguintecódigo:
List<Conta>contas=//inicializaalistadecontasvarresultado=fromcincontaswherec.Saldo>10000orderbyc.Titular.Nomeselectc;
Comissotemosumalistadecontasordenadaspelonomedotitulardeformaascendente(alfabética).Assimcomopodemosfazeraordenaçãoascendente, tambémpodemosfazeraordenaçãodescendenteutilizandoapalavradescending:
List<Conta>contas=//inicializaalistadecontasvarresultado=fromcincontaswherec.Saldo>10000orderbyc.Titular.Nomedescendingselectc;
Masesetivermosdoistitularescomexatamenteomesmonome?Nessecaso,podemosdefinirumsegundocritérioparadesempatar aordenação.Cadaumdos critériosdaordenação fica separadoporvírgula noorderby. No exemplo, para desempatarmos a ordenação utilizando o número da conta,
utilizamososeguintecódigo:
List<Conta>contas=//inicializaalistadecontasvarresultado=fromcincontaswherec.Saldo>10000orderbyc.Titular.Nomedescending,c.Numeroselectc;
Osegundocritériodeordenaçãotambémpodeteropcionalmenteapalavradescending:
Agoraéamelhorhoradeaprenderalgonovo
21.8ORDENANDOCOLEÇÕESCOMLINQ
174 21.8ORDENANDOCOLEÇÕESCOMLINQ
List<Conta>contas=//inicializaalistadecontasvarresultado=fromcincontaswherec.Saldo>10000orderbyc.Titular.Nomedescending,c.Numerodescendingselectc;
Assimcomono casodo filtro, as ordenaçõesdoLINQ também são traduzidas para chamadasdemétodo pelo compilador doC#.Quando colocamos umorderby na busca, o compilador chama o
métodoOrderBy(ouOrderByDescendingnocasodeumaordenaçãodescendente).Aquerycomo
filtroeaordenaçãopelotitularficadaseguinteforma:
varresultado=contas.Where(c=>c.Saldo>10000).OrderBy(c=>c.Titular.Nome);
Quandocolocamosumaordenaçãosecundária,ocompiladordoC#chamaométodoThenBy (ou
ThenByDescendingnocasodeumaordenaçãosecundáriadescendente):
varresultado=contas.Where(c=>c.Saldo>10000).OrderBy(c=>c.Titular.Nome).ThenBy(c=>c.Numero);
1. Vamos adicionar uma ordenação na tela de relatórios. Faça com que os botões que geram osrelatóriosmostremascontasordenadaspelaordemalfabéticadonomedotitular.
2. (Opcional) Agora tente fazer a mesma ordenação do exercício passado utilizando o métodoOrderBydoLINQ.
3. (Opcional) Tente utilizar também uma ordenação secundária pelo número da conta em seusrelatórios.
21.9EXERCÍCIOS-ORDENAÇÃO
21.9EXERCÍCIOS-ORDENAÇÃO 175
CAPÍTULO22
AgoraquejávimosquepodemosutilizaroC#paradesenvolverumsistemaorientadoaobjetos,vamosaprendercomoutilizarasbibliotecasdoSystem.IOparalereescreverdadosemarquivos.
AentradadedadosnoC#funcionaemduasetapas.Naprimeiraetapa, temosumaclasseabstrataque representa uma sequência de bytes na qual podemos realizar operações de leitura e escrita. EssaclasseabstrataéchamadadeStream.
Como o Stream é uma classe abstrata, não podemos usá-la diretamente, precisamos de uma
implementação para essa classe. No caso de leitura ou escrita em arquivos, utilizamos um tipo deStream chamadoFileStream, que pode ser obtido através dométodo estático Open da classe
File.QuandoutilizamosoOpen, devemospassar o nomedo arquivoque será aberto e devemos
informá-looquequeremosfazercomoarquivo(lerouescrever).
Paraabrirmosoarquivoentrada.txtparaleitura,utilizamosocódigoaseguir:
Streamentrada=File.Open("entrada.txt",FileMode.Open);
AgoraquetemosoStream,podemoslerseupróximobyteutilizandoométodoReadByte.
byteb=entrada.ReadByte();
Porém, trabalhar combytesnãoé fácil, queremos trabalhar com textos!Portantovamosutilizar asegundapartedaleitura.
Para facilitar a leitura de Streams, o C# nos oferece uma classe chamada StreamReader ,
responsável por ler caracteres ou strings de umStream.OStreamReader precisa saber qual é a
Streamqueserálida,portantopassaremosessainformaçãoatravésdeseuconstrutor:
StreamReaderleitor=newStreamReader(entrada);
Paralerumalinhadoarquivo,utilizamosométodoReadLinedoStreamReader:
stringlinha=leitor.ReadLine();
Enquanto o arquivo não terminar, o método ReadLine() devolve um valor diferente de nulo,
SYSTEM.IO
22.1LEITURADEARQUIVOS
176 22SYSTEM.IO
portanto,podemoslertodasaslinhasdeumarquivocomoseguintecódigo:
stringlinha=leitor.ReadLine();while(linha!=null){MessageBox.Show(linha);linha=leitor.ReadLine();}
Assimqueterminamosdetrabalharcomoarquivo,devemossemprelembrardefecharoStreame
oStreamReader:
leitor.Close();entrada.Close();
Ocódigocompletoparalerdeumarquivoficadaseguinteforma:
Streamentrada=File.Open("entrada.txt",FileMode.Open);StreamReaderleitor=newStreamReader(entrada);stringlinha=leitor.ReadLine();while(linha!=null){MessageBox.Show(linha);linha=leitor.ReadLine();}leitor.Close();entrada.Close();
Porém,oarquivopodenãoexistire,nessecaso,oC#lançaaFileNotFoundException.Devemos,
portanto, verificar se o arquivo existe antes de abri-lo para leitura. Podemos verificar se um arquivoexisteutilizandoométodoExistsdaclasseFile:
if(File.Exists("entrada.txt")){//Aquitemoscertezaqueoarquivoexiste}
Ocódigodaleituracomaverificaçãoficaassim:
if(File.Exists("entrada.txt")){Streamentrada=File.Open("entrada.txt",FileMode.Open);StreamReaderleitor=newStreamReader(entrada);stringlinha=leitor.ReadLine();while(linha!=null){MessageBox.Show(linha);linha=leitor.ReadLine();}leitor.Close();entrada.Close();}
22.1LEITURADEARQUIVOS 177
LENDOTODOOCONTEÚDODEUMARQUIVO
Vimosqueparalertodasaslinhasdeumarquivo,precisamosutilizarométodoReadLineaté
queoretornosejaovalornull,masissoétrabalhoso.
Ao invés de chamar o método ReadLine para cada linha, podemos utilizar o método
ReadToEnddaclasseStreamReader.Essemétododevolveumastringcomtodooconteúdo
doarquivo.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Assimcomoa leitura, aescrita tambémaconteceemduasetapas.Naprimeiraetapa, trabalhamosnovamenteescrevendobytesparaasaída.ParaissoutilizaremosnovamenteaclasseabstrataStream.
Para escrevermos em um arquivo, precisamos primeiro abri-lo em modo de escrita utilizando ométodoOpendoFilepassandoomodoFileMode.Create:
Streamsaida=File.Open("saida.txt",FileMode.Create);
Porém,nãoqueremostrabalharcomBytes,entãoutilizaremosumaclasseespecializadaemescreveremumStreamchamadaStreamWriter.
StreamWriterescritor=newStreamWriter(saida);
PodemosescreverumalinhacomoStreamWriterutilizandoométodoWriteLine:
escritor.WriteLine("minhamensagem");
EditoraCasadoCódigocomlivrosdeumaformadiferente
22.2ESCREVENDOEMARQUIVOS
178 22.2ESCREVENDOEMARQUIVOS
Depoisqueterminamosdeutilizaroarquivo,precisamosfechartodososrecursos:
escritor.Close();saida.Close();
Ocódigocompletoparaescrevernoarquivoficadaseguinteforma:
Streamsaida=File.Open("saida.txt",FileMode.Create);StreamWriterescritor=newStreamWriter(saida);escritor.WriteLine("minhamensagem");escritor.Close();saida.Close();
Repareque,porusarmosumaclasseabstrata,podemosentãotrocarfacilmenteaclasseconcretaporoutra.Porexemplo,poderíamos lerdeumSocket,oudeumaportaserial,eocódigoseriaomesmo:bastaaclasseserfilhadeStream.Reparequeousodeclassesabstratasepolimorfismonospossibilita
ler/escreveremdiferenteslugarescomomesmocódigo.VejaqueaprópriaMicrosoftfezbomusodeorientaçãoaobjetosparafacilitaravidadosdesenvolvedores.
OIOdoC#podeseresquematizadopelaseguintefigura:
ONDEOSARQUIVOSSÃOGRAVADOS
Quandopassamos apenasonomedo arquivono códigodoFile.Open, oC#procura esse
arquivodentrodapastaemqueaaplicaçãoéexecutada.NocasodeexecutarmosaaplicaçãopeloVisualStudio,apastautilizadapelaaplicaçãoseráapastaemqueoprojetofoicriado.
Toda vez que abrimos um arquivo dentro de um programa C#, precisamos fechá-lo utilizando ométodoClose.DevemosgarantirqueoClose seráexecutadomesmoquandoocódigo lançauma
exceçãodurantesuaexecução,paraissopodemosutilizaroblocofinally:
Streamarquivo=null;
22.3GERENCIANDOOSARQUIVOSCOMOUSING
22.3GERENCIANDOOSARQUIVOSCOMOUSING 179
StreamReaderleitor=null;try{arquivo=File.Open("arquivo.txt",FileMode.Open);leitor=newStreamReader(arquivo);//utilizaoarquivo}catch(Exceptionex){//Executaotratamentodoerroqueaconteceu}finally{//fechaoarquivoeoleitor
//antesdefecharmos,precisamosverificarqueoarquivoeoleitorforam//realmentecriadoscomsucessoif(leitor!=null){leitor.Close();}if(arquivo!=null){arquivo.Close();}}
Vejaqueocódigoparalidarcorretamentecomosarquivospodeficarmuitocomplicado.Aoinvésdecuidarmosmanualmentedosarquivos,podemospedirparaalinguagemC#cuidardogerenciamentoutilizandooblocousing.
Dentrodeumblocousingpodemosinstanciarumrecursoquequeremosquesejagerenciadopelo
C#,comoporexemploumarquivo:
using(Streamarquivo=File.Open("arquivo.txt",FileMode.Open)){//oarquivosóficaabertodentrodessebloco.}//setentarmosutilizaroarquivoforadoblocousingteremosumerrodecompilação.
TambémpodemosutilizarousingparagerenciaroStreamReader:
using(Streamarquivo=File.Open("arquivo.txt",FileMode.Open))using(StreamReaderleitor=newStreamReader(arquivo)){//aquidentrovocêpodeutilizartantooleitorquantooarquivo}
Ousingautomaticamentefechaosarquivosutilizadosdentrodoblocomesmoquandoumaexceçãoélançadapelocódigo.
Podemos utilizar o bloco using para gerenciar qualquer classe que implemente a interfaceIDisposabledoC#.
22.4EXERCÍCIOS
180 22.4EXERCÍCIOS
1. Vamosagoracriarumpequenoeditorde textopara trabalharmoscomarquivos.DentrodoVisualC#,crieumnovoprojetodotipoWindowsFormApplicationchamadoEditorDeTexto.Dentro
desseprojeto,adicioneumTextBoxqueseráocampodetextoondeousuáriodigitaráotextoque
devesergravadonoarquivo,chame-odetextoConteudo.Alémdessecampode texto,adicione
também um botão que quando clicado gravará o campo de texto em um arquivo, chame-o debotaoGrava.
Para permitir que o usuário possa digitar diversas linhas no campo de texto, clique com o botãodireitonoTextBoxeselecioneaopçãoProperties.DentrodajanelaProperties,encontrea
propriedadechamadaMultilineemudeseuvalorparatrue.AgoraestiqueoTextBoxparaqueoseuformuláriofiqueparecidocomodaimagem:
Agoraquetemosoformuláriopronto,façacomqueocarregamentodoprogramapreenchaocampodetextodo formuláriocomoconteúdodeumarquivochamadotexto.txt.Não se esqueçade
verificarqueoarquivoexisteantesdeabri-lo
privatevoidForm1_Load(objectsender,EventArgse){if(File.Exists("texto.txt")){Streamentrada=File.Open("texto.txt",FileMode.Open);StreamReaderleitor=newStreamReader(entrada);stringlinha=leitor.ReadLine();while(linha!=null){textoConteudo.Text+=linha;linha=leitor.ReadLine();}leitor.Close();entrada.Close();}}
22.4EXERCÍCIOS 181
2. Implemente a ação do botão Gravar. Quando clicado, esse botão deve gravar o conteúdo doTextBoxdentrodeumarquivochamadotexto.txt:
privatevoidbotaoGrava_Click(objectsender,EventArgse){Streamsaida=File.Open("texto.txt",FileMode.Create);StreamWriterescritor=newStreamWriter(saida);escritor.Write(textoConteudo.Text);escritor.Close();saida.Close();}
3. ExisteummétododentrodaclasseStreamReaderchamadoReadToEndquelêtodasaslinhasdo
arquivo.Modifiqueoeditorparautilizaressemétodo.
4. Modifiqueocódigodoeditordetextoparaqueeleutilizeousingparafecharosarquivos.
5. (Opcional)Quando queremos um programa que trabalha com o terminal do sistema operacional,precisamoscriarumtipodiferentedeprojetonoVisualStudio,oConsoleApplication.
Para criarmos a aplicação que usa o terminal, devemos seguir os mesmos passos da criação doWindows Form Application, porém escolheremos o Console Application na janela do
assistente.
Quandocriamosumaaplicaçãonoconsole,oVisualStudiocriaumnovoprojetocomumaclassequecontémummétodochamadoMain.ÉessemétodoqueseráexecutadoquandoapertarmosF5
pararodaroprograma.
DentrodoMain,podemosimprimirumamensagemnoterminalutilizandooConsole.WriteLine
passandoamensagem:
Console.WriteLine("Mensagemquevaiparaoterminal");
Quandoqueremos lerumalinhaqueousuáriodigitouno terminal,utilizamosumatributodo tipoTextReaderdaclasseConsolechamadoIn:
TextReaderleitor=Console.In;
NoTextReader,temosométodoReadLinequeconseguelerumalinhadoterminal.
stringlinha=leitor.ReadLine();
OReadLinedevolveumastringnãonula,enquantoousuáriocontinuarenviandonovaslinhas.
while(linha!=null){//usaotextodalinhaatuallinha=leitor.ReadLine();}
QuandoousuáriomandaacombinaçãoCtrl+zparaaaplicação,oleitordevolvenull.
182 22.4EXERCÍCIOS
CrieumprogramaquelêeimprimeaslinhasqueousuáriodigitanoterminalatéquesejaenviadaacombinaçãoCtrl+z.
6. (Opcional)Quandofizemosaleituradeumarquivo,utilizamosocódigo:
using(Streamentrada=File.Open("entrada.txt",FileMode.Open))using(StreamReaderleitor=newStreamReader(entrada)){//usaoleitor}
NoC#,oStreamReaderéumasubclassedaclasseabstrataTextReader,amesmaqueutilizamos
paralerdadosdoterminal,logopodemosreescreverocódigodaleituradearquivopara:
using(Streamentrada=File.Open("entrada.txt",FileMode.Open))using(TextReaderleitor=newStreamReader(entrada)){//usaoleitor}
Quais modificações deveríamos fazer nesse código para ler o texto que o usuário digitou noterminal?
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Precisamos tomar muito cuidado ao escrever programas que guardam informações dentro dearquivos.Comoditoanteriormente,quandoutilizamosoFile.Open,oC#procuraoarquivonapasta
emqueaaplicaçãoestásendoexecutada,porémmuitasvezesosprogramasescritossãoinstaladosempastas do sistema operacional, por exemplo C:/Arquivos de Programas, nesse caso o programa
tentaráescreveras informaçõesdentrodeumpastadosistemaoperacionalepor isso,elesópodeserexecutadoporumadministradordosistema.
JáconheceoscursosonlineAlura?
22.5 PARA SABER MAIS — ONDE COLOCAR OS ARQUIVOS DAAPLICAÇÃO
22.5PARASABERMAIS—ONDECOLOCAROSARQUIVOSDAAPLICAÇÃO 183
Normalmente,quandoescrevemosumaaplicaçãocomalgumerrodeprogramação,issonãoafetaosistemaoperacionalpoisoprogramanãoéexecutadocompermissõesdeadministradore,portanto,nãopode fazermodificaçõesperigosasno sistema.Então, paraque a aplicaçãonãoprecise ser executadocomo administrador, podemos fazer com que ela escreva, por exemplo, na pasta de documentos dousuáriologado.
Quandoqueremos recuperaro caminhoparaumapasta especialdo sistemaoperacional, podemosutilizar uma classe doC# chamada Environment do namespace System. Nessa classe, podemos
invocar ométodoGetFolderPath para recuperar o caminho para umapasta do sistema.Ométodo
GetFolderPathrecebecomoargumentoumaconstantequeindicaqualéapastaquequeremos.Para
recuperarmos o caminho para a pasta de documentos do usuário logado, podemos utilizar o seguintecódigo:
stringpastaDocumentos=Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
Os outros valores aceitos pelo método GetFolderPath podem ser encontrados nessa página:http://msdn.microsoft.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,utilizamosométodoCombinedaclassePathdonamespaceSystem.IO:
stringpastaDocumentos=Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
stringcaminhoArquivo=Path.Combine(pastaDocumentos,"entrada.txt");
184 22.5PARASABERMAIS—ONDECOLOCAROSARQUIVOSDAAPLICAÇÃO
CAPÍTULO23
EmC# textos são representados por objetos do tipo string. Para criar um texto, podemos usar a
seguintesintaxe:
stringtitulo="ArquiteturaeDesigndeSoftware";MessageBox.Show(titulo);//imprimeoconteúdo
Podemosaindajuntarduasstrings:
stringtitulo="Arquitetura"+"e"+"DesigndeSoftware";titulo+="!"//concatenaa!nofimdotexto
Usandoaconcatenação,podemosinserirovalordequalquervariávelnomeiodenossotexto:
intidade=42;MessageBox.Show("aidadeatualé"+idade);
Mas ficar concatenando strings nem sempre é fácil, principalmente se temos muitos valores.Podemosusarumaalternativa,fazendoopróprioC#fazeressaconcatenaçãopornós.Paraisso,bastaindicarnastringaposiçãoquequerinseriravariávelusandoasintaxe{posicao},epassarovalor
correspondenteemordem:
stringnome="Guilherme";intidade=42;Console.WriteLine("Olá{0},asuaidadeé{1}",nome,idade);
Casoprecisemosarmazenarastringjáconcatenadaemumavariávelaoinvésdeaimprimir,bastausarométodoFormat:
stringnome="Guilherme"intidade=42;stringtxt=string.Format("Olá{0},asuaidadeé{1}",nome,idade);MessageBox.Show(txt);
Imagine que temos uma linha de texto que separa os dados de umusuário do sistema através devírgulas:
stringtexto="guilhermesilveira,42,sãopaulo,brasil";
Comosepararcadaumadaspartesatravésda,?AclasseStringcontatambémcomummétodo
Split,quedivideaStringemumarraydeStrings,dadodeterminadocaracterecomocritério:
stringtexto="guilhermesilveira,42,sãopaulo,brasil";string[]colunas=texto.Split(',');
MANIPULAÇÃODESTRINGS
23MANIPULAÇÃODESTRINGS 185
SemprequechamamosummétodoemumobjetoString, umnovoobjeto é criado e retornado
pelo método, mas o original nunca é modificado. Strings são imutáveis. Portanto ao tentarmostransformaremletramaiúsculaoresultadopodenãoseroesperado:
stringcurso="fn13";curso.ToUpper();MessageBox.Show(curso);//imprimefn13
Sendoassim,quandoqueremostransformaremmaiúsculodevemosatribuiroresultadodométodo:
stringcurso="fn13";stringmaiusculo=curso.ToUpper();MessageBox.Show(maiusculo);//imprimeFN13
PodemossubstituirpartedoconteúdodeumaString,usandoométodoReplace:
stringcurso="fn13";curso=curso.ToUpper();curso=curso.Replace("1","2");MessageBox.Show(curso)//imprimeFN23;
Podemosconcatenarasinvocaçõesdemétodo,jáqueumastringédevolvidaacadainvocação:
stringcurso="fn13";curso=curso.toUpper().Replace("1","2");MessageBox.Show(curso)//imprimeFN23;
Àsvezesprecisamosquebrarnossostextosempartesmenorescombasenaquantidadedecaracteres,ouainda,encontraraposiçãodeumcaractereespecíficodentrodenossastring:
stringnomeCompleto="guilhermesilveira";stringnome=nomeCompleto.Substring(0,9);MessageBox.Show(nome)//imprimeguilherme;
Eparabuscarocaractereespaçodentrodeumastring:
intposicaoDoEspaco=nomeCompleto.IndexOf("");MessageBox.Show(posicaoDoEspaco);//imprime8
Ouainda,usaressesmétodosemconjunto,paraumexemplomaisavançado,noqualimprimimososegundonome:
stringnomeCompleto="guilhermesilveira";
intinicioDoSegundoNome=nomeCompleto.IndexOf("s");
MessageBox.Show(nomeCompleto.Substring(inicioDoSegundoNome));//imprimesilveira
1. Observeoseguintetrechodecódigo:
stringconteudo="16,23,34,24,15,25,35,35,54,32";
23.1EXERCÍCIOS
186 23.1EXERCÍCIOS
string[]idades=????;
foreach(varninidades){MessageBox.Show(n);}
Qualtrechodecódigodevesubstituiras???paraimprimirtodososnúmeros?
csharpconteudo.Split(',');
csharpconteudo.Replace("","\n");
csharpconteudo.Split(,);
csharpconteudo.Split('');
2. Vamosagoramelhoraroeditordetextoquecriamosnocapítuloanteriorutilizandoasoperaçõesemstring!Inicialmente,vamosincluirafuncionalidadedebuscadestringsnaaplicação.
Vamoscriarmaisumcampode textono formulárioqueseráutilizadopelousuárioparadigitarotermoqueserábuscadonoeditor.ChameessecampodetextodetextoBusca.Alémdocampode
texto, inclua tambémumbotão que, quando clicado, buscará o texto dotextoBusca dentro do
editor.Chame-odebotaoBusca.Seuformuláriodeveficarparecidocomoquesegue:
Agora que atualizamos o formulário, vamos implementar a funcionalidade de busca.Na ação dobotãodebusca,vamosutilizarométodoIndexOfparaimplementarabusca:
privatevoidbotaoBusca_Click(objectsender,EventArgse){stringbusca=textoBusca.Text;stringtextoDoEditor=textoConteudo.Text;intresultado=textoDoEditor.IndexOf(busca);if(resultado>=0)
23.1EXERCÍCIOS 187
{MessageBox.Show("acheiotexto"+busca);}else{MessageBox.Show("nãoachei");}}
Testeessanovafuncionalidadedoprograma.
3. Agoravamosimplementarafuncionalidadefind/replacequeémuitocomumnoseditoresdetextoatuais. Para isso, vamos adicionar mais um campo de texto no formulário que será otextoReplace, além de um novo botão que quando clicado trocará todas as ocorrências de
textoBuscaportextoReplacedentrodoeditor.EssebotãoseráobotaoReplace.
4. Vamosagoraadicionarumnovobotãonoformulárioquequandoclicadofarácomqueo textodoeditorfiquecomletrasmaiúsculas.UtilizeométodoToUpper()daStringparafazeressetrabalho.
5. (Opcional)AdicionetambémumbotãoqueutilizaoToLower()dastring.
6. (Opcional)Agoravamos fazer comqueobotãoToUpper altere apenasopedaçoqueousuário
selecionar do texto digitado ao invés de todo o texto. Para isso, utilizaremos duas novaspropriedades do TextBox que lidam com seleção de texto: SelectionStart e
SelectionLength.
ApropriedadeSelectionStart nos diz em qual posição, começando em 0, do texto o usuário
iniciouaseleção.SelectionLength nos devolvequantos caracteres do texto estão selecionados
atualmente.
Porexemplo,notextoabaixo:
CursodeC#daCaelum
SeousuárioselecionarapalavraCurso,SelectionStartdevolverá0eSelectionLength,5.
AgoravamosutilizaressasduasnovaspropriedadesparaimplementaroToUppernaseleção:
privatevoidbotaoToUpper_Click(objectsender,EventArgse){intinicioSelecao=textoConteudo.SelectionStart;inttamanhoSelecao=textoConteudo.SelectionLength;
//agoravamosutilizaroSubstringparapegarotextoselecionadostringtextoSelecionado=textoConteudo.Text.Substring(inicioSelecao,tamanhoSelecao);
//alémdotextoselecionado,precisamosdotextoantesdaseleção:stringantes=textoConteudo.Text.Substring(0,inicioSelecao);
//etambémdotextodepoisstringdepois=textoConteudo.Text.Substring(inicioSelecao+tamanhoSelecao);
188 23.1EXERCÍCIOS
//EagorasóprecisamosredefinirocampotextotextoConteudo.Text=antes+textoSelecionado.ToUpper()+depois;}
TentefazeromesmoparaobotãoToLower.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoC#eOrientaçãoaObjetos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
23.1EXERCÍCIOS 189
CAPÍTULO24
Muitasvezesusamosclassescriadasporoutrosdesenvolvedores,comoporexemplotodasasclassesdo.NETframework.Aclassestringéumbomexemploecheiademétodosúteismasquemdesenhoua
classenãocolocouummétodoparatransformarumapalavraemseuplural,porexemplo.Oquefazersequeremosopluralde"conta"e"banco"geradoautomaticamente?
Umaabordageméacriaçãodeummétodoestáticoquepodeserchamado:
publicstaticclassStringUtil{publicstaticstringPluralize(stringtexto){if(texto.EndsWith("s")){returntexto;}else{returntexto+"s";}}}
Claroqueessemétodoéumaabordagembemsimplesparaumalgoritmoqueécapazderetornarplurais,masjáresolveoproblemanocasogeral.Agorapodemosemtodolugardonossocódigofazer:
stringbancos=StringUtil.Pluralize("banco");stringcontas=StringUtil.Pluralize("conta");
Por mais que a implementação funcione, o código fica muito feio porque toda vez precisamosinvocarométodoestático.Nãoseriapossívelestenderaclassestringparafazeralgocomoocódigoa
seguir?
Stringtexto="banco";Stringplural=texto.Pluralize();
OC#permiteacriaçãodemétodosdeextensãoparaclassesquejáexistematravésdousodapalavrausing,maspara issodevemos colocar nossa classe estática dentrodeumnamespace e adicionar a
palavrathisaoprimeiroparâmetro:
APÊNDICE—ESTENDENDOCOMPORTAMENTOSATRAVÉSDEMÉTODOSEXTRAS
190 24APÊNDICE—ESTENDENDOCOMPORTAMENTOSATRAVÉSDEMÉTODOSEXTRAS
namespaceMinhasExtensoes{publicstaticclassStringExtensions{publicstaticstringPluralize(thisstringtexto){if(texto.EndsWith("s")){returntexto;}else{returntexto+"s";}}}}
Agorapodemos:
usingMinhasExtensoes;
stringtexto="banco";stringplural=texto.Pluralize();
Notecomo,aoimportarasextensões,todososmétodosestáticosdeclassesestáticaspúblicasdentrodo namespace importado estarão disponíveis para serem acessados como se pertencessem a classe,apesardenãopertencerem.
É importante lembrarqueométodosópodeseracessadocasoaindanãoexistaumoutrométodocomomesmonomeetiposdeparâmetrosnaclasse.Istoé,nãoseriapossívelestenderaclassestring
comumnovométodoToString()poiselejáexiste.Sópodemosadicionarnovoscomportamentos.
Exatamenteporissopodeserperigosoadicionarmétodoscomoextensõessemcuidadonenhum:nofuturoalguémpodeadicionaressemétodoàclassequeestendemoseagoranossocódigoquebrapoisnãoémaiscompatível.Somenteestendaoscomportamentosdeumaclassecasosejanecessário.
1. Queremos"adicionar"atodasasnossascontasacapacidadedeumaContasetransformaremXML.ParaissooC#jádispõeumaAPI:
usingSystem.IO;usingSystem.Xml.Serialization;publicstaticclassSerializer{publicstaticstringAsXml(Contaresource){
varstringWriter=newStringWriter();newXmlSerializer(resource.GetType()).Serialize(stringWriter,resource);returnstringWriter.ToString();}}
Paraacessaresseprocessofazemos:
24.1EXERCÍCIOS
24.1EXERCÍCIOS 191
Contaconta=newConta();System.Console.Write(Serializer.AsXml(conta));
Como desejamos usar o recurso de extensão externa doC# para poder "adicionar" ummétodo atodosascontasdosistema,oquedevemoscolocarnalinhacomentadaparadefinirnossométodo?
usingSystem.IO;usingSystem.Xml.Serialization;
namespaceCaelum{publicstaticclassObjectExtensions{//Definiçãodométodo{varstringWriter=newStringWriter();newXmlSerializer(resource.GetType()).Serialize(stringWriter,resource);returnstringWriter.ToString();}}}
//UsousingSystem;usingCaelum;Contaconta=newConta();Console.Write(conta.AsXml());
publicstaticstringAsXml(thisContaresource)
publicstringAsXml(Contaresource)
publicstringAsXml(thisContaresource)
publicstaticstringAsXml(Contaresource)
publicstaticextensionstringAsXml(Contaresource)
publicstaticstringAsXml(extensionContaresource)
2. Em vez de adicionar o extension method a todas as nossas contas, queremos incluir essecomportamentocomoextensãoatodososobjetosdosistema.Comodefiniressemétodo?
publicstaticclassSerializer{//comodefinirométodo???{
varstringWriter=newStringWriter();newXmlSerializer(resource.GetType()).Serialize(stringWriter,resource);returnstringWriter.ToString();
}}
publicstaticstringAsXml(thisobjectresource)
publicstaticstringAsXml(thisresource)
192 24.1EXERCÍCIOS
publicstaticstringAsXml(objectresource)
publicstaticstringAsXml(thisallresource)
3. Definimosumaextensãoaobjectdaseguintemaneira:
namespaceCaelum{publicstaticclassObjectExtensions{publicstaticstringToString(thisobjectresource){varstringWriter=newStringWriter();newXmlSerializer(resource.GetType()).Serialize(stringWriter,resource);returnstringWriter.ToString();}}}
Aodefinirousingadequado,qualoresultadoaochamaroToStringaseguir?
usingCaelum;Contaconta=newConta();MessageBox.Show(conta.ToString());
NãocompilapoisnãopodemossobrescreverométodoToString.
Mostraumaversãoemxmldenossaconta,ouseja,oC#usaoextensionmethod.
ImprimeoresultadotradicionaldométodoToString,ouseja,oC#nãousaoextensionmethod.
4. DadaaclasseContadefinidanoscapítulosanteriores:
publicabstractclassConta{publicdoubleSaldo{get;protectedset;}
//outrosmétodosepropriedadesdaclasseConta}
Eumaclassecomumextensionmethodparaaconta:
publicstaticclassContaExtensions{publicstaticvoidMudaSaldo(thisContaconta,doublenovoSaldo){conta.Saldo=novoSaldo;}}
Escolhaaalternativacomaafirmaçãoverdadeira.
Essecódigonãocompila,poisoExtensionMethodsópodeacessarainterfacepúblicadaConta.
Ocódigo funcionanormalmente,poiso compiladordoC# trataumextensionmethodcomosefosseummétododaContae,portanto,ométodopodeacessarosmétodoseatributosprivatee
24.1EXERCÍCIOS 193
protecteddaConta.
Ocódigocompilanormalmente,porémsópodemosusaroMudaSaldodentrodaprópriaclasseConta.
5. Sobreocódigoaseguir:
publicabstractclassConta{publicClienteTitular{get;set;}//outrosmétodoseatributosdaconta}
publicstaticclassContaExtensions{publicstaticvoidMudaTitular(thisContaconta,thisClientetitular){conta.Titular=titular;}}
Oquepodemosafirmar?
Ocódigonãocompila,poisothissópodeficarnoprimeiroargumentodoextensionmethod.
Compila normalmente e podemos usar o MudaTitular como extension method de Conta e deCliente.
Compilanormalmente,porémométodosópodeserusadocomoextensionmethoddeConta.
6. Dadasasclasses:
publicabstractclassConta{publicClienteTitular{get;set;}//outrosmétodoseatributosdaConta}publicstaticclassContaExtensions{publicstaticvoidMudaTitular(thisContac,Clientetitular){c.Titular=titular;}}
Oquepodemosafirmarsobreocódigoaseguir?
Contac=newContaCorrente();Clientetitular=newCliente("victor");ContaExtensions.MudaTitular(c,titular);
ExtensionMethodéummétodoestáticocomume,portanto,ocódigodoexercíciofunciona.
Ocódigodoexercícionãocompila.SópodemosusaroMudaTitularcomoextensionmethodenãocomométodoestático.
194 24.1EXERCÍCIOS
Ocódigonãocompila,poistemosumthisnoprimeiroargumentodoMudaTitular.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
24.1EXERCÍCIOS 195