Académique Documents
Professionnel Documents
Culture Documents
C# Pour Les Nuls
C# Pour Les Nuls
F-rst
Y,
ii/;'''!i:
;,, ::.
C#
Publi par
Hungry Minds. Inc.
9t)9
Third Avenue
Tt. 01 40'2r 46 46
Fax
0l
40 2L 46 20
E-mail : firstinfo@efirst.com
Web: www.efirst.com
ISBN: 2-84427-259-2
Dpt lgal : 1"' trimestre 2002
Limites de responsabilit et de garantie. L'auteur et I'diteur de cet ouvrage ont consacr tous leurs
efforts prparer ce livre. Hrrngry Minds et l'auteur dclinent toute responsabilit concernant la
fiabilit ou I'exhaustivit clu contenu de cet ouvrage. Ils n'assument pas de responsabilits pour ses
qualits d'aclaptation quelque objectif que ce soit, et ne pourront tre en aucun cas tenus responsables Jrour quelque perte, profit ou autre dommage commercial que ce soit, notamment mais pas
exclusivement particulier, accessoire, consquent, ou autres.
Marques dposes. Toutes les informations connues ont t communiques sur les marques dposes
pour les procluits, services et socits mentionns dans cet ouvrage. Hungry Mincls, Inc. et les ditions
First Interactive clclinent toute responsabilit quant I'exhaustivit et l'interprtation des informations. Tous les autres noms cle marque et de produits utiliss dans cet ouvrage sont des marques
dposes ou cles appellations commerciales de leur propritaire respectif.
Sommaire
Prgmire parte
2r
22
22
23
24
25
26
26
27
Deurime parte
valeur
........
3l
..........32
.............. 33
...34
.....' 35
ut
G#
37
38
38
40
40
42
43
44
44
45
45
46
46
47
49
50
5l
53
53
54
55
56
57
59
?......... 60
61
63
63
65
66
Instructions if imbriques
Les commandes de boucle
70
71
74
75
76
79
80
84
85
86
90
91
sommaire Ul
Un exemple de boucle for ..........
Troisine parte
: Programmaton et obiets...............................
9l
92
93
97
100
l0l
104
r05
106
r07
111
Pouvez-vous me cionner des rfrences ?..............
Les classes qui contiennent des classes sont les plus heureuses du monde.. 113
115
Les membres statiques d'une classe
116
Dfinir des membres de type const
116
Les tableaux : la classe Array
116
tt7
r20
r24
r27
r28
135
r37
r43
r44
r45
t46
r47
t49
l5l
157
r57
158
158
160
164
165
r68
t70
Ul
175
175
177
177
179
r82
183
184
Qu'est-ce que this ? ..............
185
this
est-il
explicite
?..............
Quand
188
Et quand je n'ai pas this ?..............
190
Obtenir de I'aide de Visual Studio - la saisie automatique ...........
Obtenir de I'aide sur les fonctions intgres de la bibliothque standard C#. 191
193
Obtenir de I'aide sur vos propres fonctions et mthodes ...........
195
200
20r
202
202
204
208
209
210
212
215
2r7
2r7
22r
223
224
Sommaire
Chapitre
I : Rendre
239
;; ";;;,pi; :
239
240
243
244
245
246
250
250
252
253
255
256
258
261
262
263
265
270
272
274
275
278
278
279
280
28r
Autres considrations
282
282
283
284
286
286
Changer de classe
Des casts invalides I'excution..........
..
288
29r
293
295
...............296
.......296
...........297
.298
IX
G#
Revenir la base
303
Le polyrnorphisme
305
306
.... 308
309
311
311
3r7
318
320
32r
325
..............
........... 359
360
362
365
367
368
37r
373
375
378
380
Somma ire
C#.........
.......... 385
... 385
................ 387
............... 388
......... 388
StreamReader
........... 390
........ 391
.394
. 396
...... 402
.... 407
409
410
410
Ma solution ..........
Dessiner la solution .............
Crer le cadre de travail de I'application Windows
Ignorez ce type qui se cache derrire le rideau
diter la fentre d'dition
Construire les menus ...........
Ajouter les contrles d'ajustement de la police
Encore un coup de peinture et nous y sommes .............
Redimensionner le formulaire ...........
Qu'avons-nous fabriqu ? ..............
Comment apprendre connaltre les composants ?
Et maintenant ?
412
412
411
413
415
417
419
422
424
426
429
431
431
433
433
435
439
439
440
442
442
444
446
446
448
XI
Xl I
G#
.. 449
crire un fichier RTF........
Mettre Lire et crire dans une bolte, avec un menu par-dessus.................. 450
Ne perdez pas mes modifications en quittant ! ..........
............. 452
. 456
Implmenter le bouton de fermeture de la fentre
Raliser vos propres applications Windows
............ 457
.......... 461
'className'n'implmentepaslemembred'interface'methodName' .. 470
471
472
Chapitre 20 : Les dix plus importantes diffrences entre C# et C++ ....... 473
Pas de donnes ni de fonctions globales
Tous les objets sont allous partir du tas
Les variables de type pointeur ne sont pas autorises..............
Vendez-moi quelques-unes de vos proprits .............
Je n'inclurai plus jamais un fichier
Index
474
474
475
475
476
477
478
478
478
479
481
lntroduction
KIU
G#
le rsultat sur n'importe quelle machine ; .NET vous dit de ne rien rcrire,
et vous pourrez excuter le rsultat sous Windows. (En principe, .NET n'est
pas directement li au systme d'exploitation Windows, mais en pratique il
y a bien peu de chances que d'autres systmes d'exploitation importants
viennent se placer sous la bannire .NET.)
C# fonctionne au mieux dans I'environnement .NET, permettant de crer
Toutefois, C# n'en est pas moins un langage autonome. Avec I'environnement Microsoft Visual Studio .NET, C# apporte aux programmeurs les
instruments dont ils ont besoin pour crer des applications harmonieuses.
Au suiet de ce liure
Ce livre a pour but de vous dcrire C#, mais il y a une difficult.
C# a t cr par Microsoft en tant que partie essentielle de son initiative
.NET. Pour des raisons sans doute politiques, Microsoft a soumis au comit
de normalisation internationale ECMA au cours de l't 2000 les spcifications du langage C#, bien avant que .NET ne devienne une ralit. En
thorie, n'importe quelle entreprise peut donc proposer sa propre version
de C#, crite pour fonctionner sous n'importe quel systme d'exploitation
Toutefois, au moment o j'cris ces lignes, il n'existe qu'un seul fournisseur qui propose un compilateur C# : Microsoft. En outre, Visual C# n'est
propos que d'une seule manire : en tant qu'lment de la suite d'outils
Visual Studio .NET.
Aussi, pour vous dcrire C#, je ne pourrai viter de vous parler de Visual
Studio, au moins jusqu' un certain point ; j'ai donc essay d'en maintenir
l'vocation un minimum raisonnable. Je pourrais me contenter de vous
dire : "Ouvrez votre programme de la manire qui vous plaira" ; mais je
vous dirai plutt : "Lancez C# partir de Visual Studio en appuyant sur la
touche F5." Je veux que vous puissiez-vous concentrer sur le langage C#
sans avoir vous casser la tte sur des questions mineures.
Introduction
D'un autre ct, je suis conscient du fait que beaucoup de lecteurs, sinon la
plupart d'entre eux, voudront utiliser C# dans le but d'crire cles applications
pour Windows. Bien que ce ne soit pas un livre sur la programmation sous
Windows en tant que telle, j'ai consacr une partie montrer comrnent C# et
Visual Studio forment, ensemble, un puissant environnement de programmation pour Windows.
Hrlpothses qratutes
Avant de pouvoir commencer programmer en C#, il vous faut avoir
install sur votre ordinateur un environnement de dveloppement C# ;
autrement dit, au moment o j'cris, Visual Studio de Microsoft. Pour
construire les programmes de ce livre, vous devez avoir install Visual
Studio .NET.
Pour pouvoir seulement excuter un programme gnr avec C#, il faut
avoir le Common Language Runtime (CLR). Au cours de sa procdure
d'installation, Visual Studio .NET copie le CLR sur votre machine. D'autre
part, Microsoft a I'intention d'inclure le CLR dans les versions ultrieures
de Windows, mais ne I'a pas encore fait pour le moment.
A
XU
XUI
direction.
Et bien sr, la sixime partie termine le livre selon la tradition des livres
Pour 1e.s 1/u/.s.
Premire partie
proqrammes c#
Dans votre vie future de programmeur C#, vous allez crer beaucoup de
programmes. Quelle meilleure manire de commencer que d'crire une
petite application Windows amusante ('ai bien dit petite) ? Cette partie
va vous montrer, tape par tape, comment crir'e la plus petite application Windows possible en utilisant l'interface Visual Studio .NET. Vous
apprendrez aussi crer le cadre de base C# que nous allons utiliser dans
le reste du livre,
Deuxitne parte
en C#
ntroduction
: Programmaton lnentaire
Troisitne parte
: Programmation et objets
Dclarer des variables ici et l et faire avec elles des additions et des
soustractions est une chose, crire de vritables programmes pour de
vritables utilisateurs en est une autre. La troisime partie est consacre
la manire d'organiser vos donnes pour les rendre plus faciles
utiliser dans la cration d'un programme.
objet
Vous pouvez toujours organiser les diffrentes parties d'un avion comme
vous voulez, mais tant que vous ne serez pas arriv lui faire faire quelque chose, ce ne sera rien d'autre qu'une collection de parties. Il pourra
aller quelque part seulement lorsque vous I'aurez fait dcoller.
C'est sur la base du mme principe que la quatrime partie va vous
expliquer comment transformer une collection de donnes en un vritable objet. Un objet qui contient diffrents lments, bien sr, mais qui
peut imiter les proprits d'un objet du monde rel. Cette partie prsente
donc I'essence de la programmation oriente objet.
XUI
XUlll
.\
mes faiblesses. Mais, croyez-le ou non, il fait a pour vous rendre service.
Il vous fait remarquer des problmes que vous auriez dt dcouvrir vousmme s'il n'avait pas t l pour a.
S%|
Cette icne indique des aspects techniques que vous pouvez ignorer en
\7 / premire lecture.
\/
= td
Introduction
L'icne Truc signale une information qui peut vous pargner pas mal de
temps et d'efforts.
f\
=(D
*-f*li3
F
l----Fr:fn
l
|
\-.Y
Souvenez-vous aussi de ce qui est indiqu par cette icne. C'est le genre
de chose qui vous tombe dessus au moment o vous vous y attendez le
moins et qui peut produire un bogue vraiment difficile dbusquer.
Cette icne identifie le code que vous trouverez sur le site des ditions
First. Vous y gagnerez quelques efforts de frappe au clavier, mais n'en
abusez pas. Vous comprendrez mieux C# en saisissant les programmes
vous-mme.
public class
MyClass
Chaque listing est suivi par une explication subtile et profonde. Les
programmes complets sont en tlchargement sur le site des ditions
First, ce qui fera votre bonheur, mais les petits fragments de code n'y
sont pas.
Enfin, vous verrez des squences d'ouverture de menus comme dans
"Slectionnez Fichier/Ouvrir avec/Bloc-notes", ce qui signifie : cliquer sur
le menu Fichier, puis, dans le menu qui apparalt, sur Ouvrir avec, et enfin,
dans le sous-menu qui apparalt, de slectionner Bloc-notes.
XIX
XX
C# pour
les Nuls
0 aller mantenant
Naturellement, la premire tape est de comprendre le langage C#, idalement en lisant C# pour les [t'luls. En ce qui me concerne, je m'accorderais
quelques mois pour crire des programmes C# simples avant de passer
l'tape suivante qui est d'apprendre crer des applications Windows. La
cinquime partie pourrait faire paratre les choses faciles, mais il y a pas
mal de piges. Essayez tous les composants disponibles dans la bolte
outils de Visual Studio. Son systme d'aide en ligne, trs complet et pratique, les dcrits tous. Accordez-vous un bon nombre de mois d'exprience
de cration d'applications Windows avant de vous lancer dans l'criture de
programmes destins tre distribus sur Internet.
Entre-temps, vous disposez de plusieurs endroits pour vous tenir au
courant de I'actualit de C#. Pour commencer, tournez-vous vers la
source officielle I nsdn . microsof t . com. Il existe aussi de nombreux sites
Web de programmeurs qui contiennent des lments trs complets sur
C#, et qui permettent aussi de participer des discussions en ligne sur
les sujets les plus divers, de la manire d'enregistrer un fichier source aux
mrites combins des ramasse-miettes (garbage collectors) dterministes
et non dterministes. Voici quelques grands sites sur C#, sans ordre
particulier
,/
www.
t/
csharpindex.
t/
r^/ww.
c- sharpcorner. com
J'ai aussi mon propre site Web, wlvw. stephendavls . com, qui contient une
liste de questions frquemment poses (FAQ, Frequently Asked Questions). S'il y a une chose que vous n'arrivez pas comprendre, Ia rponse
ce qui vous proccupe s'y trouve peut-tre dj. J'y ai aussi ajout une
liste de toutes les erreurs qui ont pu se glisser dans le livre. Enfin, il y a
un lien vers mon adresse de messagerie qui vous permettra de m'envoyer
un mail si vous ne trouvez pas ce que vous cherchez.
Premire partie
Greruos premiers
programmes c#
Ilr
tt:
t I
V
ici ce que vous ayez maltris C#, vous avez pas mal de
chemin faire. Autant commencer par vous amuser un
peu. Cette premire partie va vous montrer les tapes de la
cration d'une application Windows aussi simple que possible
en utilisant I'interface de Visual Studio .NET. Vous y apprendrez
aussi crer le cadre de travail de base en C# pour les exemples
de programmes qui apparaissent tout au long de ce livre.
Chapitre
Grervotre premier
programme c#pour
Wi ndows
Dans ce chapitre :
Qu'est-ce qu'un programme ? Qu'est-ce que C# ? O suis-je
C#
1t$!Qa. Pour des raisons historiques, le langage machine est aussi appel langage
d'assemblage. Chaque constructeur fournissait avec ses machines un
programme nomm assembleur qui convertissait des mots particuliers en
instructions du langage machine. Ainsi, vous pouviez crire des choses
vraiment cryptiques du genre l'{OV AX, Ci{ (c'est une vritable instruction
pour processeur Intel), et I'assembleur convertissait cette instruction en
une suite de bits correspondant une seule instruction machine.
{cg)
Qu'est-ce que C#
comble le foss qui existait entre le puissant mais compliqu C+* et le facile
mais limit Visual Basic. Un fichier de programme C# porte I'extension .CS.
C# est
t/
t/
t/
t/
t/
,/ Sr:
Tout langage destin une utilisation sur Internet doit contenir sous une forme ou sous une autre des outils de scurit pour se
protger contre les hackers.
.NET est la stratgie adopte par Microsoft dans le but d'ouvrir le Web
aux simples mortels comme vous et moi. Pour comprendre cela, il vous
faut en savoir un peu plus.
Il est trs difficile de programmer pour Internet dans des langages un peu
anciens comme C ou C++. Sun Microsystems a rpondu ce problme en
crant le langage Java. Celui-ci repose sur la syntaxe de C++, rendue un peu
plus accessible, et est centr sur le principe d'un dveloppement distribu.
^tK
'qg,
C#
Crer le nodle
crire une application Windows partir de zro est un processus clifficile,
c'est bien connu. ll y a beaucoup de gestionnaires de sessions, de
descripteurs, de contextes, beaucoup de dfis relever, mme pour un
programme simple.
Visual Studio .NET en gnral et C# en particulier simplifient considrablement la tche de cration d'une application Windows, mme dj trs
simple. Pour tre franc, je regrette un peu que vous ne soyez pas oblig
de tout faire la main. Si le cur vous en dit, vous pouvez essayer avec
Visual C**. . . Mais je n'insiste pas.
Comme le langage C# est conu spcialement pour faire des programmes
qui s'excutent sous Windows, il peut vous pargner bien des complications. En plus, Visual Studio .NET comporte un Assistant Applications qui
permet de crer des modles de programme.
Typiquement, un modle de programme ne fait rien par lui-mme, en tout cas
rien d'utile (un peu comme la plupart de mes programmes), mais il vous fait
passer sans effort le premier obstacle dr,r dmarrage. Certains modles de
programme sont raisonnablement sophistiqus. En fait, vous serez bien
tonn de tout ce que l'Assistant Applications est capable de faire.
*\
q/\
'e,
l.
2.
porte I'extension
.PRJ.
.-.il
&5dnsr*s
t ---?t
t,-dI
ffi
P66 de
trvd
'-l
,.!
omarage
.fu
xptor*eur Windows
Arcessoires
,..& Internt
,#
.p
:!
t*il,***
Explorer
outlookExpress
outils Microsoft office
"|ffi, Mi..rlt1utlod.,
Windws Update
Nouveu dscumffit Of f ic
ffi
ftl
j
-:i
,$
NicroscftExrd
tticrosdt t4ord
,NET
Frm$,rk5D{
lP
Figure 1.1:
La ligne
droite n'est
-pas le plus
court chemin
du Bureau
c#.
;fioemaner
3.
ir
3J
tlglts
rl^6
4.
Pour cet exemple, vous pouvez utiliser le nom par dfaut ainsi que
I'emplacement par dfaut pour Ie nouveau dossier : Mes
documents\Projets Visual Studio\Wi nd owsAp p 1 i c at i on 1 .
t0
C#
Figure 1.2
Crer un
n0uveau
projet vous
met sur la
voie d'une
:
a pplication
Windows.
f;g iiJ
Figure 1.3
L Assistant
Applications
-de Visual
studio est
prt crer
p0ur v0us un
nouvea
pr0gramme
Windows.
w
de 'lepl,:ienre
I
| lll
:J1
<t
Prijet de
':reatron
Emplacement
ffi
@
Fibtiottreowde
-*
A5P,FIET
Eibliothque de
contrles U/eb
AFliration
AsF'.rJE
Ert,liothque de
,:,lnlrlBs
",LlindDi!5
,-
;|
Parcourir
,..
vtlus
5.
T- "l --l
Annuhr
Aid*
t\r
^"9FK
7 ,31ll )
\g/
Dgnns
:
g'-til5
Debuq
'
Fentre
Help
-#
Forml
5ystem,Wrrdorys
fl:l e,
f--l z
l.-l zr l@l /
B , ;. ..,.u.,""
, ArressibleDescfl
r AaessrbleNdnre
Forrn5.Ffr w
i AccessibleRole Defaqlt
; h?rrn,:rttt
dtrloror
Ll Lontror
; EacksroundlmogtI iaucun)
: aursor
Oefault
:E) nont
l'rrosol't 5ans 5el
ForeColor I
Conhol1ext
1
j
E
Figure 1.4 :
Le modle de
pr0gramme
initial pour
Windows n'a
rien de bien
Gerrrat rorl
5izble
Rightl0teft
Text,
Forml
No
False
{aucunl
True
Nofontrl
El (Dyndfri.Propertr
:
4 l:,*.1t4't.,,,. t,,.-,,.
ext
-,
{
La gnration a rursi
FrmBsrder5tl,l
Coll
Chl
tl
l2
G#
Figure 1.5
La fentre du
modle
-d application
Windows
fonctionne,
mais elle ne
suffit pas
convaincre
que Visual
Studio.NET
vaut son prix.
- 1t${Qa.
{dg)
Pendant que vous y tes, mettez donc jour votre CV pour y faire savoir que
vous tes officiellement un programmeur d'application Windows. Pour le
moment, vous pouvez vous contenter de mettre "application" au singulier.
DDnns
,:ompsnts
'r/y'rndows Forn-rs
\
A
A
tatel
gll
E.rttc'n
Fc,inteur
LinLLabel
iii,r-
Te:<tBo:r
$
lv
(.
Marnf"lenu
Figure 1.6:
La Bote
-dl
Picture8x
outils de
Visual Studio
contient une
quantit de
contrles
!
.9
ll
:g
;:-
utiles.
Presi-F,piers cirr:ulire
LneaxDox
HlOtrUtf0Tl
Grupuox
-.j
;:
h'Anel
natacrid
ListBctx
checkedlist8ox
L0mBoErlx
Llslvre({
Gnerni
t3
t4
C#
.$$G ^/
t(7,
V
Hinquitezpas.VotreBo1teoutilspeuttrsbiensetrouvergauche,
l.
2.
la premire.
3.
4.
Figure 1.7
Mon
Wi
''
formulaire
0.
est srement
plus beau
+1lx
Iter:tE'rr:1
...
ltertEr'irj
....
que le vtre.
rllatri ser
le
s propri ts
l.
2.
3.
t5
t6
button
f-'=l
s;
| .- I dr
-t
frl,a1
lt9 | /
G#
Butt'ln
Default
n'
Copier
FlaL5lyle
5tandard
l-aJTtl:
Ftrefol,:r
!
[--l
Inr,rqe
fontrolText
(nurun)
Inr,r'lelgn
Ivliddlefenter
Intaqelrr,le;r
l-l
RighlT,:Lel't
No
lnucun)
f"liddle,lerrter
Figure 1.8
La fentre
Proprits
v0us 0ermet
de matriser
vos contrles.
E | ..,,,i.,,,;r..
'
llr,r+Dr,:p
IdIS
aonLe:rtlt:rrU
I UCUn
ttralogResult
l,l:rne
. l':l:l:l
':
Text
D.
Figure 1.9:
Dfinir une
zone de texte
en lecture
seule
(Read0nly)
empche
lTape:
,.i,t'ar:i .- :
progal]w
-r:.l,tf:r.,r
L. .:.l
l'utilisateur
de modifier
le champ
c0rrespondant.
Gnrer l'application
Pour gnrer I'application, slectionnez Gnrer/Gnrer. Cette action
gnre une nouvelle application Windows avec le formulaire que vous
venez de crer. Si elle n'tait pas dj ouverte, la fentre Sortie apparat,
dans laquelle vous voyez dfiler le flot de messages dont le dernier doit
-ltrl
Figure 1.10:
La fentre du
pr0gramme
lrEEtrEE@
formulaire
lle
-est le
que v0us
venez de
crer.
t7
t8
l.
2.
3.
4.
textBoxl
textBox2.Text = textBoxl.Text;
1r${Qa^
ftg)
minuscules).
ll 'i
.3:
t'.
l?f
I'tt
PJojet
-.
,' Forml,cs*
Ferr
:':)',
!bog,:er
utils
:l
:J
[::l rl, fa
L.,_l:r IEI
l.:'T-.Tl1r 1ll
:-lf,l1r
!r:,lal llil]til
Figure 1.11
La fonction
de sugges-
1r
>l
+r
5rne
proprits au
fur et
mesure que
vous tapez.
:t*
Z
; :,.;,, .. E
ssrtie
Pret
Col 40
5.
tg
20
G#
zone de texte cible, comme le montre la Figure 1.12. Vous pouvez joyeusement rpter le processus autant que vous voulez avec tout ce qui vous
passe par la tte, jusqu' ce que l'puisement vous submerge.
-ltrlxJ
lJ'ai tap r,ea darrr la zone de lerte t.rurrte
lJ'ai tap ceci dan le asne de texte srrurce
Figure 1.12
a marche
bien difficile.
^tK
'qE,
Ceux d'entre vous qui sont des programmeurs Visual Basic ont peut-tre
une impression de dj vu. En fait, le Concepteur de formulaires fonctionne assez largement comme les dernires versions de I'environnement
Visual Basic, mais il est beaucoup plus puissant (en tout cas, par rapport
aux versions antrieures Visual Basic .NET). Le langage C# en lui-mme
est d'ailleurs plus puissant que le prcdent Visual Basic. La bibliothque
de routines .NET est plus puissante que I'ancienne bibliothque de Visual
Basic. Enfin, .NET prend en compte le dveloppement distribu et en
diffrents langages, ce que ne faisait pas Visual Basic. En clehors de tout
cela, je dirais qu'ils sont peu prs identiques.
Chapitre 2
Grervotre premire
application console en C#
Dans ce chapitre :
Crer une application console plus maniable'
ne me
dcourageant pour le programmeur c# dbutant. si vous
type
du
programme
croyezpas, alleisimplement voir Ie Chapitre 1. Un
de
moins
qu" t'on appelle application console gnre significativement
code c# et est beaucoup plus facile comprendre.
crer un modle
Dans ce chapitre, vous allez utiliser Visual Studio afin de
peu manuelleun
d,application console, que vous allez ensuite simplifier
pour
bon nombre
ment. Vous pourrez utifiser le rsultat comme modle
des programmes que je prsente dans ce livre'
parties) est de
Le principal but de ce livre (en tout cas des premires
pour
qui
aura un succs
ySP*E
faire en c# un ieu
\ ;J; aider comprendre c#.
\ -.i
!g:I
langage c#'
\ 5
l
que vous connaissiez le
I mondial, il faut d'abord
22
C#
l.
Visual Studio affiche une fentre contenant des icnes qui reprsentent les diffrents types d'application que vous pouvez crer.
2.
Application
console.
f\
/
e,
.--).
ConsoleApplicationl. L'emplacement par dfaut du fichier correspondant est un peu trop en profondeur mon gott dans le dossier
Mes documents. Puisque je suis un peu difficile (ou peut-tre parce
que j'cris un livre), je prfre classer mes programmes o je veux,
et pas ncessairement l o Visual Studio veut les mettre.
3.
4.
5.
System;
nanespace He11o
tt
lll
(rrmlnary)
||
Suwary description
|
III
for
Classl.
4tsw*nary)
class
Class1
ll
/l
il
args)
]
'l
f\
=(t
Tester le rsultat
Slectionnez Gnrer/Gnrer pour faire de votre programme C# un
programme excutable.
23
24
Dbut de
Debug ,NEf -
---Gnration
:I
,hv-
I a russi.
Unerglegnraledelaprogrammationestque''aruSSi''Veutdire,,a
f fxll
tL]r,
-
.,-.71r{
LL?r,
-
-rr
r\V-
^1
using Systen;
namespace IIe1lo
t
^!!hr.^
PUUTfL
LrAD
^t^^a
I,^.SS1
UrA
Chapitre
string
/i
Console.hlriteline("He1Lo,
"*
sNane)
Console.ReadO;
Le programme rpond par le mot "Hello", suivi par le nom que vous avez
entr. Puis il attend que vous appuyiez sur Ia touche Entre pour rendre
4${ea^
Eramnons ce programme
Dans les sections qui suivent, nous allons prendre part I'une aprs I'autre
chaque partie de cette application console en C# afin d'en comprendre le
fonctionnement.
25
26
G#
System;
nanespace Hel1o
C'est
ici
le
que coruaenc
prograrnme
//
ici
l
l
L'instruction using Sysrem peut venir juste avant ou juste aprs I'instruction namespace Hel1o l. L'ordre dans lequel elles se prsentent n'a pas
d'importance.
Les commentares
Ce modle contient dj un certain nombre de lignes, et j'en ai ajout
commentaire.
^}kt
ftXl
lLvrf
\SrZ7
-
Toute ligne commenant par lloupar lll es:une ligne de texte libre qui
sera ignore par C#. Pour le moment, vous pouvez consiclrer ll eI lll
comme quivalents.
.qa/
ft}Il
\\f/
La substance du lrrogramme
Le cur de ce programme se trouve dans le bloc de code dlimit par
I'instructionMain i ):
/l
1'utilisateur
console.l,lriteline("Entrez votre
ll tit
string
/l
nogl:
Console
")
.l,Jriteline ("He11o
,"*
nom
sName)
Entrez votre
nom:.
27
28
G#
Console.Read0;
"tq-$,j
-i
il
x
T .t
Deuxime partie
Programmation
lmentaire en C,#
Chapitre 3
32
int
n'
I'
Malheureusement pour les programmeurs, C# impose plusieurs limitations aux variables - limitations dont les mathmaticiens n'ont pas se
soucier (sauf ceux qui s'aventurent lire ce livre).
exemple
x=yl
+zy+y
si k:
,, + 1 ^1^-^
I ' ! qrur
x=k2
Ici, le mathmaticien a crit une quation quadratique. Peut-tre les variables x et y ont-elles dj t dfinies quelque part. Toutefois, lorsqu'il voit
apparaltre une nouvelle variable, k, le programme tombe des nues. Dans
cet exemple, ft ne signifie pas essentiellement qu'il a la valeur de y plus 1,
mais qu'il reprsente le concept de y plus 1. C'est une sorte de raccourci.
Jetez un coup d'il n'importe quel manuel de mathmatiques, et vous
veyyez ce que je veux dire. Je dis bien : jetez un coup d'cril. Vous tes ici
pour lire mon livre et pas un autre.
Un programmeur doit tre prcis dans Ia terminologie qu'il utilise. Par
exemple, il peut crire le code suivant :
i nt
dit : "n gale 1." Le programmeur C# le dit d'une manire plus prcise : "Stocker la valeur I dans la variable n." (Pensez
I'armoire dossiers suspendus, et vous veyrez que c'est prfrable.) Les
oprateurs C# disent I'ordinateur ce que vous voulez faire. Autrement
dit, les oprateurs sont des verbes et non des descripteurs. L'oprateur
d'assignation prend la valeur qui est sa droite et la stocke dans la
Le mathmaticien
^tK
=({g,
Qu'est-ce qu'un i
rrt .)
crit
- rl. t
n
.. = .| . -l. t
n
n
: Maison
* ttleg llartiens
sont panni
nousn
33
34
C#
Avant de pouvoir utiliser une variable, vous devez la dclarer. Une fois
que vous avez dclar une variable de type int, elle peut contenir et
rgurgiter des valeurs entires, comme le montre I'exemple suivant :
IT
'i
nf
Dc1are une
variable entire
avec 1a valeur
int
et f initialise
m = ?'
Assigne
n=
La premire ligne aprs le commentaire est une dclaration qui cre une
zone de stockage, n, faite pour contenir une valeur entire. Aussi longtemps qu'il ne lui est pas assign une valeur, la valeur initiale de n n'est
pas spcifie. La deuxime dclaration cre une variable entire m, avec 2
\g/
valeur 3 5
Vous pouvez dclarer une variable n'importe o (en fait, presque n'importe
o) clans un programme, mais vous ne pouvez pas utiliser une variable
avant de I'avoir dclare et de lui avoir donn une valeur. Les deux instruc-
int
pi
int
de dffrents
tapes
int. C# en offre un certain
nombre de variantes pour quelques occasions particulires.
La plupart des variables simples sont de type
Toutes les variables de type int sont limites aux nombres entiers. Le
type int souffre aussi d'autres limitations. Par exemple, une variable de
type int ne peut stocker de valeur qu' I'intrieur de l'tendue -2 milliards
1t$!Qa^
; Lt 'rilliards.
't
^.v7atr
L'tendue exacte est de -2 147 483 648 2 147 483 647.
:(dqfl
)
\/
^s}K\
^..?r
vra
\-/
\J/
;l-\
\E/"
36
.r$c ./
Autrement dit, un entier iong occupe deux dossiers d'une capacit d'un
HintclansvotrearmoiredossierSSuSpendus'Commecettemtaphore
t(7,
Y
^.rr7p7\ L'tendue
'qg,
exacte d'un entier long est de -9 223 372 036 854 775 808
C# offre plusieurs autres types de variable entire montrs par le Tableau 3.1.
Taille
sbyte
byte
(octets)
tendue
Exemple
-128 127
sbyte sb = 12;
0255
byte b = 12;
short
-32,768 32,767
short Sr = 123456',
ush ort
0 65,535
int
-2 milliards 2 milliards
1nt
uint
0 4 milliards
uint un = 3234567890U
long
-101s
ulong
1020
101e
(beaucoup)
n = 1234567890;
long | = 1234567890121
long ul = 123456789012U1
Comme je I'expliquerai dans la section "Dclarer des constantes numriques", plus loin dans ce chapitre, une valeur fixe telle que 1 a aussi un
type. Par dfaut, une constante simple comme 1 est considre de type
int. Une constante de type autre que int doit tre marque par son type.
Par exemple, l23U est un entier non sign (unsigned), de type ui irt.
La plupart des variables de type entier sont signes, ce qui signifie qu'elles ont un signe (+ ou -), et qu'elles peuvent donc reprsenter des valeurs
Fahrenheit
jusqu' l'infini.
Une variable int ne peut reprsenter que des nombres entiers. L'quivalent
i(-9t4K
ilfi ) entier de 37,78 est 37. Cette manire d'escamoter la partie dcimale d'un
nombre pour le faire tenir clans une variable entire s'appelle tronquer.
\g)
Sf f
i({",'
=l
1.
Arrondir
1,9
37
38
G#
:HW
entiers.
Dans bien des cas, vous aurez besoin de nombres dont la partie dcimale
n'est pas nulle. Les mathmaticiens les appellent les nombres rels. J'ai
toujours trouv a ridicule. Y a-t-il des nombres entiers qui soient irrels
-sq4<o
./
i:
=( UA )
N7/
Remarquez que j'ai dit qu'un nombre rel peut avoir une partie dcimale
non nulle, mais ce n'est pas obligatoire. Autrement dit, 1,5 est un nombre
rel, mais 1,0 galement. Par exemple, 1,0 + 0,1 gale 1,1. Un nombre rel
plus un nombre rel donne un nombre rel. Gardez cela en tte pour la
suite de ce chapitre.
float f =
1.0:
Une fois dclare comme f 1oat, la variable f est de type f loat pour
toutes les instructions qui vont s'y appliquer.
que la virgule dcimale
\eENrgr. Un nombre virgule flottante doit son nom au fait
"flotter"
y
gauche
est
autorise
lieu
de
droite
au
de se trouver un
S/^T \
permet
fixe.
Il
reprsenter
emplacement
donc
de
aussi
bien 10,0 que 1,00
=ldl\y /
\/ ou 0,100, ou tout ce que I'on peut imaginer.
.
float
double
-$tf,
Taille [octets]
Etendue
1.5
16
*
5.0 10324
* 10'45
3.4
* 1038
x
1.7
10308
Prcision
Exemple
chiffres
15 - 16 chiffres
float f
6-
= 1.2F;
double d = 1.2:
Le type par dfaut pour une variable en virgule flottante est double et
nonr :.--'
Dans le Tableau 3.2, la colonne Prcision contient le nombre de chiffres
exacts pour chaque type de variable virgule flottante. Par exemple, la
fraction 5/9 vaut exactement 0,555... avec une infinit de 5. Mais une
variable de type f loat contient un certain nombre de chiffres exacts, ce
qui veut dire que les chiffres qui se trouvent au-del du sixime ne le sont
pas ncessairement. Aussi, exprim dans le type f loat, 5/9 pourrait trs
0,5555551457382
Vous savez donc que tous les chiffres apparaissant aprs le sixime 5 ne
peuvent pas tre considrs comme exacts.
-rK
'qg,
Une variable de type f loat possde en fait 6,5 chiffres exacts. Cette
valeur trange vient du fait que la prcision en virgule flottante est donne par un calcul qui fait intervenir 10 puissance un logarithme en base 2.
Voulez-vous vraiment en savoir plus ?
39
40
G#
Avec une variable de type double, la mme fraction 5/9 pourra apparaltre
de cette facon :
0.tt555555555555555 iB2323
Le type double possde quant lui entre
.st 1
l5 et
16 chiffres exacts.
Hprcision(letypedoub1e),vouspouveZutilisercetype,moinsd'avoir
Itgrf
s---'r
-
en virgule flottante.
g,O)
C'est mieux que les problmes de robinet que I'on apprenait rsoudre
cole primaire.
est vrai qu'elles utilisent plus de mmoire, mais de nos jours la nrmoire
ne cotte pas cher. Alors, pourquoi pas ? Mais les variables virgule
flottante ont aussi des limitations.
Aussi, si vous ajoutez l,l ce que vous voyez comme 1,1, vous ne
pouvez pas savoir a priori si le rsultat est2,2 ou 2,200001. Et si vous
demandez "dDoubleVariabie est-elle gale 2,2 ?", vous n'aurez pas
forcment le rsultat que vous attendez. En gnral, vous allez devoir
vous en remettre une comparaison un peu factice comme celle-ci :
"La valeur absolue de la diffrence entre dDoubleVariable et 2,2 est-elle
4l
42
C#
La ttitesse de calcul
Les processeurs de la famille x86 utiliss par les PC un peu anciens fonctionnant sous Windows faisaient les calculs arithmtiques en nombres
entiers beaucoup plus vite que les mmes calculs avec des nombres en
virgule flottante. De nos jours, ce serait sortir de ses habitudes pour un
programmeur que de limiter son programme des calculs arithmtiques en
nombres entiers.
Avec le processeur Pentium III de mon PC, pour un simple test (peut-tre
trop simple) d' peu prs 300 millions d'additions et de soustractions, le
rapport de vitesse a t d'environ 3 1. Autrement dit, pour toute addition en type double, j'aurais pu faire trois additions en type int (les
calculs comportant des multiplications et des divisions donneraient peuttre des rsultats diffrents).
Ae/!!\ viter les effets de cache. Le programme et les donnes taient mis en
9(dW ) .a.he, mais le compilateur ne pouvait mettre en cache dans les registres
\/ du CPU aucun rsultat intermdiaire.
Une tendue pas si limite
Dans le pass, une variable en virgule flottante pouvait possder une
tendue beaucoup plus large qu'une variable d'un type entier. C'est
toujours le cas, mais l'tendue du type long est assez grande pour rendre
la question pratiquement dpourvue d'intrt.
f\
=Q)
t/
fraction.
t/
Comme une variable entire, offrir une valeur exacte utilisable dans
des calculs. Par exemple, 12,5 est effectivement 12,5, et non
12,500001.
d e c 1ma 1
rn1:
= 100;
rn3 = 100M:
m2
/l
ll
ll
Bien
Mieux
Eneore nieux
initiale. Tant que vous ne lui aurez pas assign une valeur, son contenu
est indtermin. C'est sans importance, car C# ne vous laissera pas
utiliser cette variable tant que vous ne lui aurez pas donn une valeur.
La seconde dclaration cre une variable rn2 et lui donne 100 comme
valeur initiale. Ce qui n'est pas vident, c'est que 100 est en fait de type
int. C# doit donc convertir cette valeur de type int n type decimal
avant de I'initialiser. Heureusement, C# comprend ce que vous voulez
dire et effectue la conversion pour vous.
La dclaration de m3 est Ia meilleure des trois. Elle initialise m3 avec la
constante de type decimal 100M. La lettre M la fin du nombre signifie
que la constante est de type decimal. $/oyez la section "Dclarer des
43
44
dec
ima 1,
int, et f1 o at
Une variable de type dec imal semble avoir tous les avantages et aucun
des inconvnients des types int et double. Elle a une trs grande tendue, elle n'a pas de problmes d'arrondi, et 25,0 y est bien 25,0 et non
25,00001.
Le type decimai a toutefois deux limitations significatives. Tout d'abord,
une variable de type decimal ne peut pas tre utilise comme compteur,
car elle peut contenir une partie dcimale. Vous ne pouvez donc pas vous
en servir dans une boucle de contrle de flux, comme je I'explique au
Chapitre 5.
Le second inconvnient du type decirnal- est tout aussi srieux, ou
mme plus. Les calculs effectus avec des variables de ce type sont
significativement plus lents que ceux effectus avec des variables de
type int ou f1cat. Je dis bien "significativement". Mon test simple de
300 millions d'additions et de soustractions a t peu prs cinquante
fois plus long qu'avec le type int, et je souponne que ce rapport serait
encore plus dfavorable avec des oprations plus complexes. En outre,
la plupart des fonctions de calcul, comme les exponentielies ou les
fonctions trigonomtriques n'admettent pas le type decimai.
Il est clair que le type decinal convient trs bien auxapplications comme
la comptabilit, pour lesquelles la prcision est trs importante mais le
nombre de calculs relativement rduit.
peut prendre deux valeurs : true ou f alse (vrai ou faux). Je parle srieusement : un type de variable rien que pour deux valeurs.
tgq\Qa. Les programmeurs C et C** 6n1 I'habitude d'utiliser une variable i-nt avec
^t7q \ la valeur 0 (zro) pour signif ier f a 1 s :,r, et une valeur autre que zro pour
)
signifier tru.e. a ne marche pas en C#.
\/
:(dw
Il n'existe aucun chemin de conversion entre une variable bool et tous les
autres types. Autrement dit, vous ne pouvez pas convertir directement
une variable bool en quelque chose d'autre (et mme si vous pouviez,
vous ne devriez pas, parce que a n'a aucun sens). En particulier, vous ne
pouvez pas transformer une variable bool en int (par exemple sur la
base du principe que false devient zro), ni en string (par exemple sur
la base du principe que false devient "fa1se").
Toutefois, une variable de type bool joue un rle important pour forcer
I'excution d'un programme C# suivre tel ou tel cheminement, comme je
I'explique au Chapitre 5.
char c - tat;
45
46
Une variable de type char n'est pas associe une police. Vous pouvez
^nu1$Q( trs bien y stocker un caractre Kanji que vous trouvez trs beau, mais
+/
.--., \
t^-.
tO /
V,,/
si
Tqpes
char s1rciaur
Valeur
nouvelle ligne
'v'
tabulation
'\0'
caractre null
'\r'
retour chariot
'\\'
Le trlpe
string
string soneStringl;
soneStringl = "eeci est une chane";
I
une chaine";
Une variable de type string ne peut pas tre utilise comme compteur, et
ce n'est pas un type contenant une valeur. Il n'existe aucune "chalne" qui ait
une signification intrinsque pour le processeur. Seul un des oprateurs
+ effectue
'rteci est
un nembre de uhrase
string
s la chalne suivante
t en voiL un autre'l
Encore un mot : une chane ne contenant aucun caractre (que I'on crira
"") est une chalne valide.
^
Conparer
string t char
47
48
Les rgles qui s'appliquent aux chalnes ne sont pas les mmes que celles
qui s'appliquent aux caractres. Pour commencer, une variable char ne
contient par dfinition qu'un seul caractre. Le code suivant, par exemple, n'a aucun sens :
char cl l1.
char c2 = rht.
char c3 =c1*c2
^"tK
'qE,
quent la conversion de c1 en une variable int qui reoit la valeur numrique du caractre initialement contenu dans c 1, puis la mme chose pour
c2, eT finalement I'addition de ces deux entiers. L'erreur se produit lorsque I'on essaie de stocker le rsultat dans c3. Une valeur numrique de
type int peut pas tre stocke dans une variable de type char, par
dfinition plus petite. En tout cas, cette opration n'a aucun sens.
Une chane, en revanche, peut avoir une longueur quelconque, et la
concatnation de deux chalnes a un sens :
_+_.i-^
Lr{rr
^1
r
il^ilr
a
a+r'.ina
L!rrr
1
4
llhll
u
.
t
strjnq
s3
"ab"
La rgf e gnrale estque le nom d'un objet autre qu'une variable doit commencer par une lettre
majuscule. Choisissez des noms aussi descriptifs que possible, ce qui signifie bien souvent des
noms composs de plusieurs mots. Chacun de ces mots doit commencer par une majuscule
{sauf le premier dans le cas d'une variable}, et ils doivent tre colls les uns aux autres, sans
tre relis par des tirets de soulignement, comme ceci : ceciEsrUnlcngNomDeVariable
J'ai aussi adopt la rgle supplmentaire selon laquelle la premire lettre du nom d'une
variable en indique le type. La plupart de ces lettres sont assez explicites : f pour f 1oat, d
pour double, s pour string, et ainsi de suite. La seule qui ncessite un petit effort de
mmoire est n pour int. ll y a toutefois une exception cette rgle : pour des raisons qui
remontent au langage FOfiTRAN des annes soixante, les lettres i, j, et k sont couramment
utiliss seules comme nom pour les variables de type int.
Remarquezque j'aiditavoir"adopt" cette convention. Ce n'estpas moiquil'aiinvente, mais
quelgu'un qui travaillait chez Microsoft l'poque du langage C. Comme il tait d'origine
hongroise, rette convention a reu le nom de notation hongroise.
La notation hongroise semble ne plus tre en faveur. Je continue toutefois la prfrer, car
elle me permet de connatre du premier coup d'il le type de chaque variable dans un
programme sans avoir me rfrer la dclaration.
49
50
.6
Les types int, double, L-.oii, et leurs drivs immdiats, comme int non
sign, sont des types de variable intrinsques. Les types de variable
intrinsques, ainsi que Ie type decinal, sont aussi appels types valeur.
Le type string rr'est ni I'un ni I'autre.
Les types dfinis par le programmeur, que je dcris au Chapitre 6, ne sont
ni des types valeur, ni des types intrinsques.
-of4q
^-/ -t- \ ':-/
-i
) I oute expressron
II
Dans une dclaration comme int n, vous pouvez facilement voir que la
variable n est de type int, et vous pouvez raisonnablement supposer que
le calcul n * 1 est de type int. Mais quel est le type de la constante 1 ?
Le type d'une constante dpend de deux choses : sa valeur, et la prsence
optionnelle d'une lettre descriptive la fin de celle-ci. Tout nombre entier
infrieur 2 milliards est suppos tre de type int. Un nombre entier
suprieur 2 milliards est suppos tre de type 1ong. Tout nombre en
virgule flottante est sutrtpos tre de type double.
Le Tableau 3.4 prsente des constantes dclares pour tre d'un type
particulier. La lettre qui sert de descripteur peut tre aussi bien en
Type
Lnt
onod
.),'.- * int
iU
rinqi
1L
long int
1.0
d o ui:,
1e
Constante
Type
1.0F
f!IUAL
I ^-r_
1M
decimal
t rue
bool
^1^^
I.1 LbC
bool
r-l
a
^t^-
'\n'
'\x123'
"a string"
valeur 5 |
LllAt
123)
string
s
' '
Lnanger ae rype
.'
le cast
int
nValue = 10;
long lValue;
1Va1ue = nValue;
//
ceci fonctionne
int
10;
nValue;
nValue =
lValue;
ceei est
illicite
lnt
52
Certaines valeurs que l'on peut stocker dans une variable de type long
sont trop grandes pour une variable int (par exemple, 4 milliards). Dans
ce cas, C# gnre une erreur, car des informations pourraient tre perdues dans la conversion. Ce type de bogue est trs difficile identifier.
Mais si vous savez que la conversion est possible ? Par exemple, bien que
lVa1ue soit de type 1cng, peut-tre savez-vous que sa valeur ne peut pas
dpasser 100 dans ce programme. Dans ce cas, la conversion de la variable de type long iValue en variable nValue de type int ne poserait aucun
problme.
Vous pouvez dire C# que vous savez ce que vous faites en utilisant un
CqST:
long
int
1Va1ue
10;
nValue;
nValue
Dans un cast, vous placez entre parenthses le nom du type que vous
voulez obtenir, juste avant le nom de la variable convertir. Le cast cidessus dit : "Convertir en int la valeur de 1Va1ue. Je sais ce que je fais."
Un nombre qui peut tre utilis comme compteur peut tre converti automatiquement en type f 1oar, mais la conversion d'un nombre en virgule flottante
en nombre pouvant servir de compteur ncessite un cast:
double dValue = 10.0;
1t$!ea.
des
Chapitre 4
^qa/
ff"ll
\f/
crire un programme qui fait vraiment quelque chose, c'est bien. Si vous
n'y arrivez pas, vous ne devien drezjamais un vritable programmeur C#,
moins, bien str, que vous ne soyez un consultant, comme moi.
Fare de l'arithnt4ue
L'ensemble des oprateurs arithmtiques est divis en plusieurs groupes : Ies oprateurs arithmtiques simples, Ies oprateurs d'assignation,
et un groupe d'oprateurs spciaux, propres la programmation. Une fois
que vous les aurez digrs, il vous faudra faire de mme pour un autre
ensemble d'oprateurs : les oprateurs logiques.
5tt
Signification
- (moins unaire)
diviser
additionner
- (moins binaire)
so ustra i re
modulo
int nl * 5;
int n2 = -nl ;
n2 a naintenant 1a valeur -5
L'oprateur modulo vous est peut-tre moins familier que les autres. C'est
tout simplement le reste d'une division. Ainsi, 5 % 3 vaut 2, et 25 % 3 vaut
1e$!Qa.
rqr,/-t \
'qE,
1(25-3.8).
La dfinition stricte de I'oprateur
7u
est : "x = (x I y) * x
Yo
y"
Les oprateurs arithmtiques autres que modulo sont dfinis pour tous
les types numriques. L'oprateur modulo n'est pas dfini pour les types
en virgule flottante, car une division effectue en virgule flottante n'a pas
de reste.
intn:5
Est-ce que le programmeur veut dire "multiplier 5 par 3 et ajouter 2", ce
qui fait 17, ou bien "multiplier 5 par la somme de 3 et 2", ce qui fait 25 ?
-efr{c
j5:
S/
=(
\
$g ,
intn*241612
D'autre part, les oprateurs ont une hirarchie, ou ordre de priorit. C#
commence par examiner I'expression, et excute les oprations en commenant par celle qui a le niveau de priorit le plus lev. Dans mes prcdents
livres, je me suis donn le plus grand mal pour expliquer la priorit des
oprateurs, mais je me suis depuis rendu compte que ce n'tait qu'une
perte de temps (et de neurones). Il vaut toujours mieux se dbarrasser de
la question de la priorit des oprateurs en utilisant les parenthses.
De cette faon, la valeur de I'expression suivante est claire, quel que soit
int
n = (7
3) * (4 + (6 / 3));
int
n = (7
3)
(4 + 2);
int n = 1 *
6;
55
56
C#
intn=7
Cette rgle connat peut-tre une exception. Je trouve ce comportement
intolrable, mais de nombreux programmeurs omettent les parenthses
dans des exemples comme le suivant, car tout le monde sait que la
priorit de la multiplication est plus leve que celle de I'addition :
intn*7*2n3;
Le rsultat de cette expression
3;
Dans cet exemple, 5 * 3 vaut 15 et est de type int. L'oprateur d'assignation stocke la valeur de type int qui se trouve sa droite dans la variable
de type int qui se trouve sa gauche, et retourne la valeur 15. Mais ce
n'est pas tout, cette nouvelle conception de I'oprateur d'assignation
autorise la forme suivante :
m
=n=5
3;
autre oprateur.
sympas 5 7
int
int
n -
n;
m;
n = 1.
Par exemple
n
**
1;
Il existe un tel oprateur d'assignation pour pratiquement tous les oprateurs binaires. Je ne sais pas exactement comment ils sont venus au
monde, mais pourtant, ils existent.
L' o p
Parmi toutes les additions que I'on peut avoir faire dans un programme,
la plus courante consiste ajouter I une variable
:
- n * 1;
1;
++n;
Les
/l
incrruente n de I
de la valeur
58
int
n;
n=
1;
int
++n;
n
rt = Ij. t
int
= n**;
Gn
Les compilateurs d'aujourd'hui sont plus astucieux, il n'y a davantage de diffrence entre le
n*1, donc plus de besoin pour un oprateur
temps d'excution de n** et celui iJe n
sympas 59
d'incrmentation. Mais les programmeur$ ssnt des cratures qui ont leurs habitudes, st cet
oprateur est toujours l. Vous ne verrez presque jamais un programmeur C++ incrmenter
ull:rri3.ble en utilis.ant la,forme plus longue mais plus intuitive n n*1. Vous le verrez
plutt utiiiser l'oprate ur d' inc rm e nttin.
D'autre part,lorsqu'on le rencontre isol {c'est--dire pas I'intrieur d'une expression plus
- est-ce logi4ue .)
b
a>b
a >= b
a<b
(= b
a l= b
==
int n = 5;
int n * 6t
bool b * n )
n;
60
Cet exemple assigne la valeur f alse la variable b, car 5 n'est pas plus
grand que 6.
Les oprateurs de comparaison logique sont dfinis pour tous les types
numriques, notamment f 1oat, double, decimal, et char. Tout ce qui suit
est licite
bool b;
b = 3 ) 2;
b = 3.0 ) 2.0;
;;; ;;;;
_
ib=10M)12M;
i
float f1;
float f2;
fl
= 1fl'
f.2 =
f.I |
3i
bool b1 = (3
1/
tt
* f2)
==
fl;
4.
sympas 6 I
devrait tre true si le rsultat du calcul est un peu dcal par rapport la
comparaison.
lrpU{a"
At^tJ\ Pour faire un peu mieux, vous pouvez utiliser de la faon suivante la
fonction de valeur absolue pour comparer f 1 et f 2
=HlW
\/ )
:
Math.Abs(d1
- 3.0 -
dZ)
.00001; //choisissez
le niveau de prcision
ment gales.
Oprateur
!a
a est
a&b
a et b sont
alb
a^b
a&&b
a et b sont
true
all
a ou b sont
true
a est
false
true
t rue
ou b est
true
true
xor
b)
62
G#
^dK
'qg,
Les oprateurs &, | , et n existent aussi dans une version que I'on appelle
oprateur de bits. Appliqus une variable de type j-nt, ils oprent bit par bit.
Ainsi, 6 &3vaut 2 (01102 &00112 donne 0010t, 6 I 3vaut 7 (01102 i 00112
donne 01112), et 6 ^ 3 vaut 5 (01102 ^ 00112 donne 01012). L'arithmtique
binaire est une chose extrmement sympathique, mais sort du cadre de cet
ouvrage.
Les deux derniers oprateurs logiques sont semblables aux trois premiers, mais prsentent une diffrence subtile avec eux. Considrez
I'exemple suivant
L'oprateur
sions :
&&
\',lix lfej|
Y
llu
ll
(boolExpression2);
.
,
n=5
*5t
7:
Ma calculatrice me dit que n vaut 32, mais cette expression a aussi un type.
int*int*int
int * int
int
tYPe3
63
64
G#
int
uint
long
float
* int
* uint
* long
* float
{9---2 1nt
@- -
-) uint
@---) long
@---) float
* decimal @- - -)
*
double double @---)
decimal
Ainsi,2*
type
decimal
double
3 utilise la version
int * int
de I'oprateur
* pour produire 6, de
int.
Connersion de tqpe
inltlcite
Tout cela est trs bien pour multiplier deux int ou deux f loat. Mais
qu'arrive-t-il lorsque les deux arguments ne sont pas de mme type ? Par
exemple, dans ce cas :
int nl = 10:
double d2 = 5.0;
double dResult =
nl *
d2;
sympas 6 5
le cast
Vous pouvez toujours changer le type d'une variable d'un type valeur en
utilisant I'oprateur cast. Un casf consiste mettre entre parenthses le
type dsir et le placer immdiatement avant Ia variable ou I'expression
concerne.
De cette faon, I'expression suivante utilise I'oprateur
int
n1
1;
double 2 = 5.0;
int nResult = nl
Le cast de
int * int
2 en l
- (int)d2;
Laissez la logi4ue
tran(uille
Assigner un tqtte
Le mme principe de compatibilit de types s'applique I'oprateur
d'assignation.
66
=f
^f\1|
\!!_/
10;
( * n1.
E J.V
ttLt
tout-puissant type
oub 1e.
Toutefois, les types de ce qui est droite et gauche de I'oprateur d'assignation doivent tre compatibles, mais le type de ce qui est gauche ne
peut pas changer, car C# n'accepte pas de rtrograder implicitement une
expression. Le compilateur gnre donc le message d'erreur suivant :
int nl -
1o;
expression2
sympas 67
int a: 1:
int b = 2;
intnMax=(a)b)?a:b;
Dans cet exemple, si a est plus grand que b, la valeur de I'expression est
a. Si a n'est pas plus grand que b, la valeur de I'expression est b.
int a:
1;
double b = 0.0:
intnMax=(a)b)?a:b;
int a = 1;
double b = 0.0;
int
/I
nMax;
ceei fonctionne
nl{ax
* (int)((a ) b) ? a :
//de
mme
b)
que ceci
nMax=(a)b)?a:(int)b;
Vous aurez rarement I'occasion de voir une utilisation de l'oprateur
ternaire.
Chapitre 5
narnespac
, t,
/Je
prograrnme coru[ence
static
lcl
//tit
1'utilisateur
Console
70
l
l
]
fr
\(Ll
if
1f
(bool expression)
/l
ici si
nrrp
Chapitre
I garantir
ll si st
ir(a()
I
tl
a
que a
. alors,
assigner
0;
l
Ce fragment de code permet de garantir que la variable a est toujours
suprieure ou gale zro. L'instruction if dit : "Si a est infrieur 0,
alorsassigner0a."
.rK
=qE,)
"if (expression
boolerne)
instruction"
Et si
i'a
du prineipaL
intrt
decinal nlnterestPaid ;
mlnterestPaj.d = nPrincipal t (nlnterest / tOO)
le total
/1calcu1e naintenant
-;;i".ip.i-i
nnterestPaid ;
u;.tni--t;;;i
7t
72
_-"-ffi
,
//
II
ll
II
II
o-
using
v--ve-.
System;
Interest
nanespace Calculate
L
public class
Class1
public static
le principal initial
: ");
string sPrincipal = Console.ReadLine0 ;
1I tnrr]-nclpalr \/
^\
u/
l
//demande 1'utilisateur d'entrer le taux d'intrt
Console,llrite("Entrez 1e taux d'intrt :") ;
if
(mTntprest
\Ir+..
Lv-
vv
0)
nlnterest
0;
le total
decirnal motal = nPrincipal *
//affiche rsultat
(nlnterest
tOO)
//ca1cu1e maintenant
mlnterestPaid;
Console.l,lriteline("Taux d'intrt
Console
llriteline
* nPrincipal)
* " * nlnterest *
"%");
Console
Console.Read0;
return
0i
^9\./
ft}il
\r/
o$!9{r
SZ- ^\
(t
/
V--/
contres
Taux
=
Principal
d'intrt =
Zlol
rntert pay =
1t,
259.14
1234
73
74
Total
Appuyez
G#
1493.14
Principal
Taux
7X
t(9,
Y
1234
Intert pay =
Total
1234
Appuyez
^$$G t
d'intrt = 0%
Pour que le source soit plus lisible, mettez en retrait les lignes d'une
instruction if. C# ne tient pas compte de la mise en retrait. Beaucoup
d'diteurs de code comporte une fonction de mise en retrait automatique : chaque fois que vous tapez la commande 1f , le texte correspondant
est mis en retrait automatiquement. Pour activer cette fonction dans
Visual Studio, slectionnez Outils/Options, et cliquez sur le dossier
diteur de texte. Parmi les sous-dossiers de celui-ci, slectionnez C#, et,
dans ce dernier, Tabulations. Dans cette page, slectionnez Mise en
retrait Intelligente, et dans la zone Tabulations, spcifiez la taille du
retrait que vous voulez (en nombre d'espaces). Pour ce livre, j'ai utilis
une mise en retrait de deux espaces.
mar
conserr/
conne maxinun
= ai
Ghapitre
if (a (= b)
I
max
conserve
conne maxinum
= b;
e1s e
I
max
= b;
Si a est plus grand que b, c'est le premier bloc de code qui est excut.
*...
^
EUlrcf meme
rc e-Lse
Les squences de plusieurs clauses else peuvent donner une certaine
confusion. Certains programmeurs, dont moi-mme, prfrent les viter
lorsque a permet de faire un code plus clair. On pourrait crire le calcul
du maximum de la facon suivante :
// stocke
int max;
et b
76
//
^
--^-J l-^-! L -1,.rttp hsuppose que d
PJ-u l.duu
nax = 8;
I I si ce n'est
if(b)a)
nec lo
n.c
ll
max
lnstructions
if
inbrques
if
I
I
||
II
II
I
I
est
Le programme suivant,
instructions
if
intrt
ngatif, alors
et n'effectue pas le
using
programme 7
ca1cu1.
System;
natuespace CalculatelnterestWithBmbeddedTest
t
public class
Class1
naxinun
IL
else
t
I
sinon,
demande 1e
taux d'intrt
I lsi
l
erse
1
deux 'ralides
//p1us lrintrt
decimal mlnterestPaid ;
mlnterestPaid * mPrincipal * (nlnterest / 100);
/lca1eule naintenant 1e tstal
decimal motal * nPrincipaL * mnterestPaid;
t
ar,
1
r.
rsultat
/affiche
f I
Consol"e.l,lriteline0
; //
ConsoLe.I,lriteLine()
skip a line
"%"):
onsole.Writeline("Intrt
Console.l,lriteline
('tTotal
C#
pay = tr + mlnterestPaid);
=
rt + nlotal)
llattend confirmation
de
1'utilisateur
. . ")
Console.Read0;
Le programme commence par lire Ia valeur du principal entre par I'utilisateur. Si elle est ngative, il affiche un message d'erreur et se termine. Dans le
cas contraire, Ie contrle passe la clause e1se, et le programme poursuit
son excution.
Dans cet exemple, la vrification du taux d'intrt a t amliore. Le
programme demande ici un taux d'intrt qui ne soit pas ngatif (rgle
mathmatique) et qui soit infrieur un maximum (rgle juridique). Cette
instruction i
if
(mlnterest
( 0 ll
nlnterest
nl'laxinumlnterest)
t\\vl
I/....fil
l\rt
L
Placer les constantes dans des variables au dbut du programme est utile
plusieurs titres. Tout d'abord, chaque constante a ainsi un nom :
nMaximunlnterest est beaucoup plus descriptif que 50. D'autre part, elles
sont beaucoup plus faciles retrouver dans les expressions. Enfin, il est
beaucoup plus ais d'en changer la valeur en cas de ncessit. Remarquez
que c'est n|laxinunlnterst qui apparat dans le message d'erreur. Si
vous remplacez nl4axi:,nurnlnterest par 60, par exemple, cette modification n'affecte pas seulement le test, mais aussi le message d'erreur.
Si I'utilisateur entre une valeur correcte pour le principal mais un taux
Le taux
Appuyez
Principal
Taux
= 1234
d'intrt = 12.5
r,
Total
Appuyez
ilyaunprogrs.
Ce qu'il vous faut, c'est un moyen pour I'ordinateur d'excuter plusieurs
fois la mme squence d'instructions. C'est ce qu'on appelle une boucle.
79
80
;l:rie
1
--1-
\-
La premire fois que I'instruction de boucle while est rencontre, I'expression boolenne est value. Si elle est vraie, le code contenu dans Ie bloc
qui suit est excut. Lorsque I'accolade qui en indique la fin est rencontre,
I'excution reprencl I'instruction wl'ri 1e. Ds que I'expression boolenne
est fausse, le bloc de code qui suit est ignor, et l'excution du programme
passe clirectentent ce qui suit.
Si la condition n'est pas vraie la premire fois que I'instruction
wliile
st
cfq-'.'
=,:c|,,)
boucle.
Vous pouvez utiliser I'instruction ',;fri i e pour raliser le programme
Cari:lll..tie-r.i.:,r ,jl'iab1e., Qui est une version en boucle du programme
Ca i c,,r 1 a t e I r i e r e s *.. Ca i c u1 at e 1 i t e r e s t TaL i e calcule une table des
valeurs du principal pour chaque anne, en mettant en vidence I'accumulation des ir-rtrts annuels :
urrr JyLcur,
nmpsn2c
l.qirrLUPsu!
Ce
r^rrlatelntereStTable
"^
u!lr
"-^
Q"^+^-.
/Lcl4,
programme
public class
C1ass1
initial
1r {mHr1nc1nl \
.
an+
rrtrBdLl!.
c>L n-.+i1
nrln.1h.1
yrarrLfyof
a
uJ
^\
ll
else
{
sinon,
denande 1e
taux d'intrt
nnterest =
0;
l
e1s e
{
vaLides
:")
int
("Principal
une
ligne blanche
Console.Writeline("Dure ='tf
Console.l,,lriteLi.ne
lleffectue
inf
nerr
nDuration
"ans");
= l'
while(nYear (= nDuration)
{
deci.mal mlnterestPaid
mlnterestPaid = mPrincipal
* (mlnterest I
100);
8l
82
//f intrt
au principal prcdent
2)
+ rr - rr + nTPrincipal
l
attend confirmation de 1'utilisateur
Console,Vlriteline("Appuyez sur Entre pour terminer. . .")
II
Console.Read0;
l
L'essai d'excution de ce programme donne ce qui suit
Principal
= 1234
d'intrt = L2.5'l'
= 10 ans
Dure
Taux
- 1388.25
2-1561.78
3-1757
4-r97 6 .62
5-2223.7
6-2501.66
7 -2814,37
B-3166.1i
9-3561,94
10-4007.18
Appuyez sur Entre pour
terniner,
1ep!Qa"
{dg)
1r$!Qa"
7^T \ L'instruction decirnal
=\l\y j
\/
Round ( )
plus proche.
nYear
t 1; incrmente
nYear de
1.
^9\.1
(Gil
\Zl
qui.ontiste
Calc.rlatelnterestTable
doit tre dclare et initialise avant la boucle while dans laquelle elle est
utilise. En outre, I'incrmentation de la variable nYear doit gnralement
tre la dernire instruction de la boucle. Comme le montre cet exemple,
83
84
G#
>/
tl ^,,\I
\t/
Lorsque vous crivez une boucle r'hi 1e, n'oubliez pas d'incrmenter la
variable servant de compteur, comme je l'ai fait dans cet exemple :
\-----./
int
nyer = 1;
^\
instructions,
I'ordinateur).
.l
Faites attention ce que la condition de sortie de la boucle puisse rellement tre satisfaite. En gnral, il suffit pour cela que la variable compteur
soit correctement incrmente. Sans cette prcaution, vous tes bon pour
Et maintenan\
o...
wh
i 1e
Il existe une variante de while :c'est la boucle dc... whiie. Avec elle, la
condition n'est value qu' la fin de la boucle :
int
nYear
= J;
do
t
I
instructions.
nYear = nYear * 1;
while (nYear ( nDuration);
-q\!C ^,
J'ai
I[qIl
\Zl
Hdoutequ'ilyaitbeaucoupdeprogrammeursquisesouviennentseulement
1t
(mPrincipal
(maxPorrer
n0riginalPrincipal)
t!
break;
j
La commande b reak ne sera excute que lorsque la condition de I'instruction if sera vraie. Dans ce cas, lorsque la valeur calcule du principal
sera suprieure maxPower multipli par la valeur initiale du principal.
L'excution de la commancle break fait passer le contrle en dehors de la
',.t$f$
'./
F
ha"
f-fiT.X.)
I li'/
Vous trouverez sur le site Web une version du calcul de table d'intrt qui
comporte cette adjonction (il serait un peu long d'en donner le source ici).
Principal
Taux
100
d'intrt = 25i,
Dure
= 100 ans
85
86
si la valeur initiale
Arrter
10
1-r25
2-156.25
3-195.31
4-244.14
5-305,1B
6-381.4B
7-476.85
B-596.06
9-745.08
10-93 I .35
i1-1164.19
nnrrrroz
crlr
Fntr
nnrrr
tarminor
tln I
r"rr
leMo
reFors.ivins
,,^i-urrr6 O,,^r^-.
y LEul,
//
denande
continue
:,,^^,, t:a Lc
^^ Yu
^,,',,ne
u
rI rI JuDgu
decinal mPrincipal;
while (true)
{
;
;
lt lmfrlnclpaL )=
i
u)
^\
break
]
I
onro
11n
mpsso
rl'errerrr si
val
Console.l'lriteline
//
maintenant
demande
decinal nlnterest:
whi.1e
(true)
break;
]
I
.et
Console,illriteline0;
]
Console.
:"
,'
Console
// effectue
+'
mPrrnnlh
srr!frj!rHufl'
I t.
87
88
int nYear = 1;
/l
i/
ll
l'lnteret
decinal mlnterestPaid
mlnterestPaid = mPrincipal n (mlnterest I t0O);
l/ calcule naintenant le nouveau principal en ajoutant
:
Console.I^Iritetine(nYear + rf -fr
// oasse 1'anne suivante
nYear = near
nPrincipal)
proche
1;
Ce programme fonctionne largement de la mme manire que les exemples prcdents, sauf pour ce qui est entr par I'utilisateur. Dans ce cas,
c'est une boucle while eui remplace les instructions 1f utilises prcdemment pour dtecter les entres invalides. Par exemple :
decinal mPrincipal:
while (true)
{
;
:
mPrincipal = Convert.ToDecimal(sPrincipal) ;
I I sort de 1a boucle si valeur entre est valide
if (mPrincipal )= 0)
{
L
break;
|X
IICff I
\z
{f\
q/
e,
z<r- \
Vous allez peut-tre trouver cela vident, mais I'expression true est value
comme true. Par con-cquent, while (true) est I'archtype de la boucle
infinie. C'est la commande break qu'elle contient qui fait sortir de la boucle.
Aussi, si vous utilisez une boucle while (true), faites particulirement
attention ce que la condition de break puisse tre satisfaite.
Veuillez
recommencer
Veuillez
recomnencer
Princinel
000
50
8g
90
Taux
G#
d'intrt = 10%
Dure
=5
ans
t - 1100
z'!trv
1^i^
3 - 1331
4-1464.r
5-1610.51
Appuyez sur Entre pour
terniner...
hriables
Une variable dclare dans le corps d'une boucle n'est dfinie que dans
int
nDays
while(nDays
1;
nDuration)
{
.in+ n,,nra^a
-LllL rlvIBtr
nDays
n\/c1rro
= llvoauc
LLUqJ D t
I/ nllrrr<.
instructions
= nDays
1;
^2K
:(dqf
\/
programme
or
(initflxpressioni condition
increnent[xpression)
instructions.
Lorsqu'une boucle
whiie suivante
initExpression;
hile (condition)
t
instructions.
incrementExDression;
l
Un evemlrle de boucle f
d'une boucle f or
1/ instructions
a=
1;
C#
9l
92
G#
1)
IL
corps de
la
boucle
]
I
a^ = 1,
L.
1 ;. Il
Supposez que le programme vienne d'excuter I'instruction a
dclare ensuite la variable nf ear t I'initialise 1. Cela fait, il compare
near nr)urar,rcr,. Si rrYear est plus petit que rrDulaiion, le corps de la
boucle (les instructions contenues dans les accolades) est excut.
Lorsqu'il rencontre I'accolacle fermante, le programme revient en haut de
la boucle, et excute I'expression rrYear : nYeai: * i avant d'effectuer la
comparaison nTear
nDurar-ion.
Chapitre
for(int
nYear
= l;
nYear
( nDuration; nYear*i)
i
I
.corps de 1a boucle
.q$q ,.,
Hdansunebouclefor,pluttquel'oprateurcleprincrmentation,bienque
t(9,
Y
I'effet en soit le mme dans ce cas. Il n'y a pas d'autres rai.sons cela que
I'habitude et le fait que a a I'air plus cool. (On m'a dit que a marchait trs
bien pour briser la glace. Rien n'est moins str, mais vous pouvez toujours
essayer d'exiber votre code, tout hasard.)
infinie.
.$a/
ft?ll
NV|
for(
,condition
.)
fnr l'
!vr
,r1tr
conditi.on
.)
t
I
corps de 1a boucle
l
l
-.sg4le
t(
Une boucle incluse dans une autre est entirement excute chaque
passage de la boucle qui ia contient'
1g )
93
e4
do
do
for(
.)
.)
] while (
]
I
I
ltin
lfin
Je ne suis mme pas trs sr de ce que a voudrait dire, mais c'est sans
// boucle for A
.condition
for(
L,
i'r.?,'r'.
.)
// boucle for B
for(
.autre condi.tion
,)
II
if (.
.
.
break:
B nais pas de
]
]
]
:, r'g.11.,
boucles.
1t${a.\
^v7-y
eHq9
\/
..rtlga
p"
I 'l*
r
ffit-'l
Hl
programme
//
I
DisplayXWithNestedloops
- utilise
using
System;
nanespace DisplayXWithNestedloops
{
I Ie
= ' t;
I si Ie numro de la ligne est ga1 celui de 1a colonne...
if (nColumnNun == nRovNum)
char c
I
IL
='\\':
c
l
',
'l
c o'/';
I
I
Console.l.lriteline 0
I5
96
C#
l
l
=Qt
"t\
:::l(rtllJ"il?'i;Ji'n""
\
\
\
\
Appuyez
*-o"uli3
f--t-i..(.)
I t\t
chl
if (nMaritalStatus =:
0)
I
]
e1s e
t
if (nMaritalStatus == 1)
I
.utres instructions
Et ainsi de suite.
97
98
case 0:
instructions si clibataire.
break;
1.
^^^^
LA
l.
instructions si mari.
break;
case 2:
instructions si divorc.
break;
case 3:
I
instructions si veuf.
break;
case 4:
I
break;
default:
I lpasse ici quand aucun cas ne correspond
probablement une condition d'erreur
;
//c'est
break;
break;
]
s)
case ttDavistt:
I
le contrle
break;
case "Srnith":
I
instructions si mari.
1^-^^1,.
cse "Jones
I
"
instructions si divorc.
ring
break;
case "Hvidsten":
tl
instructions
si veuf.
break;
default:
/l
o1t^r1n n.c
passe i^.i.rro..l
r.u anrrecnnnd
rLr 9UOllU AULUII
LAJ n
break;
j
,/
L'argument de
s-,,;i
cl'ur-r
ou de type str:iii:.,.
,/
t/
t ch.
t/
t/
string s = "Davis";
switch (s)
{
case ttDavigtt:
case "Hvidsten':
lltait
mme
break;
case "Smith":
I
break;
default:
reak
passe
;
ici
99
100
C#
Le modeste goto
Vous pouvez aussi transfrer le contrle d'une manire non structure en
utilisant I'instruction goto. Elle est suivie par I'un des lments suivants:
t/
Une tiquette.
t/
t/
tion sw,tch.
Le fragment de code suivant montre comment est utilise I'instruction
gcto
le contr1e
IL
passe de goto
1'tiquette spcifie
goto exitlabel;
]
I
exitlabel
1e
r"odc
L'instruction goto est impopulaire, pour les mmes raisons qui en font
une commande de contrle si puissante : elle est presque entirement
dpourvue de structure. Si vous I'utilisez, il peut tre extrmement
difficile de maltriser le flux de I'excution au-del d'un petit morceau de
code particulirement trivial.
.$sc ./
Hfait,lelangageC#lui-mmeatcritiqupouravoiradoptcetteinstruc-
t\?,
Y
Tioisime partie
Programmation et obiets
'yoil {Trzan en avoir rnrre I Encore
mauvais message I Quoi a veut dire zt
TarZan tout essayer lTrzan furieux
comrne Cheetah
Ghapitre 6
Dans ce chapitre :
Les classes en C#.
|04
tableaux
I
I
//
//
I
non du nod1e
non du construcreur
nomhrp d nortcs du vhicule
nombre de roues du vhicule
.gtt\
o/
Yi
.'-<) \
C# fait la diffrence entre les majuscules et les minuscules dans les noms
de classe, comme pour tous les autres noms utiliss en C#. C# n'impose
aucune rgle sur les noms de classe, mais il existe une rgle non officielle
selon laquelle le nom d'une classe doit commencer par une majuscule.
Le nom d'une classe est suivi par une accolade ouwante et une accolade
fermante. Entre ces deux accolades apparaissent les membre.s que comporte
ventuellement cette classe. Les membres d'une classe sont des variables qui
en constituent les lments. Dans cet exemple, la classe Vehicie commence
par le membre string sModel, qui contient Ie modle du vhicule. Si c'est une
voiture particulire, le nom du modle pourrait tre "Eldorado". Vous en voyez
certainement tous les jours. Le second membre de notre exemple de classe
Vehicle est str:ing sllanufacturer, qui contient naturellement le nom du
constructeur. Enfin, les deux dernires proprits sont le nombre de portes et
le nombre de roues du vhicule.
Comme pour toute variable, donnez aux membres d'une classe des noms
aussi descriptifs que possible. Dans I'exemple ci-dessus, j'ai ajout des
commentaires la dclaration de chaque membre, mais ce n'tait pas
ncessaire. Le nom de chaque variable dit clairement de quoi il s'agit.
L'attribut publec eui prcde le nom de la classe rend celle-ci universellement accessible en tout endroit du programme. De mme, I'attribut pubiic
plac devant le nom d'un membre de la classe le rend tout aussi accessible
en tout endroit du programme. On peut galement utiliser d'autres attributs.
Le Chapitre 11 traite en dtail la question de I'accessibilit.
| 05
106
Une dfinition de classe doit dcrire les proprits d'un objet qui joue un
rle incontournable dans le problme rsoudre. C'est un peu difficile
faire dans I'immdiat, parce que vous ne savez pas encore quel est le
problme, mais je suppose que vous voyez o je veux en venir.
Dfinir une classe Vehic 1e n'est pas la mme chose que de construire une
voiture. Vous n'aurez pas ici emboutir de la tle ni visser des crous.
Un objet classc se dclare de faon semblable, mais pas tout fait identique, un objet intrinsque.
D'une faon gnrale, le terme objet signifie "quelque chose". a ne nous
aide pas beaucoup. Une variable int est un objet int. Un vhicule est un
objet vehrcle. Vous-rnme, vous tes un objet lecteur. Quant moi, je
suis un auteur...
Le fragment de code suivant cre une voiture de la classe Vehic 1e
Vehicle
myCar =
myCar;
ner^r
Vehicle0
int
h11m.
nun
1,
num
Chapitre
[.a prernire ligne dclare la variable num, et la deuxime ligne stocke dans
I'emplacement dfini par la variable nr-iin une constante dj existante de
type int.
mmoire I'objet
1t${Qa^ Il y a en fait une diffrence dans la rnanire de stocker en
\
intrinsque nun et I'objet mvCar. La constante 1 n'occupe pas de mmoire,
^.v7q
car le CPU et le compilateur C# savent dj I'un et I'autre ce qu'est un "1".
N{ais votre CPU ne sait pas ce qu'est un ehicle. L'expression ne,,r
-,i
ehic Le alloue l'espace mmoire ncessaire la description d'un objet
,,'-.hrcJ e pour le CPU, pour C#, et pour le reste du monde.
'(cg,
1r!!{a"
Aa,/
1;
Toute opration en C# doit tre value par type aussi bien que par
myCar est un objet du type ehic ie. La variable
','ei''ic1e. nliuinbe,rOf Doors est cle type int (voyezla dfinition de la
classe Vehicle). Comme la constante 5 est aussi de type int, le type de
ce qui est droite de l'oprateur d'assignation est le mme que celui de
ce qui est gauche.
e(dw
\.,
= "Izeta";
(L'lzeta tait une petite voiture construite pendant les annes cinquante,
dont I'unique porte constituait toute la face avant.)
107
I 08
,t
Fortran (de la fin des annes cinquante au dbut des annes quatre-vingtl : pas de
notion de classe.
tl
C{delafindesannessoixante-dixaudbutdesannesquatre-vingtdix} :lesclasses
ne sont utilises qu' des fins d'organisation. ll est possible d'crire des progrrnmes
t/
C++ {du milieu des annes quatre-vingt aujourd'hui) : la notion de classe y est
beaucoup plus volue, ll esttoujours possible d'crire des programmes qui ne s'en
servent pas, mais seulement en se limitant un sous-ensemble du langage.
,/
Java (du milieu des annes quatre-vingt-dix auiourd'hui) : la notion de classe y est
fondamentale. lmpossible d'crire du code sans y avoir recours.
,/
C#
La notion de classe a pris une importance croissante parce que les programmeurs se sont
rendu compte que les classes taient trs efficaces pour reprsenter des objet du monde
rel. lmaginez par exemple que je sois en train d'crire un programme de gestion de comptes
bancaires. Un compte bancaire prsente des caractristiques telles que le nom de son
titulaire, le numro du compte, le solde, et le nom de la banque. 0r, je sais bien que ces
proprits font partie d'un mme ensemble, car elles dcrivent toutes le mme objet: un
compte de ma banque. Connatre le solde sans connatre le numro du compte correspondant, par exemple, n'a aucun sens.
string contenant
contenant le numro du compte, une variable double
ou dec ima1, contenantle solde, une variable st ring contenantle nom de la banque, et ainsi
de suite. Un seul objet de la classe BankAccount contient donc toutes les proprits.
pertinentes pour mon problme, d'un compte bancaire donn.
En C#,ie
int
Ghapitre
t/
t/
t/
t/
|/ lr"hinlalaraonlrr
donne une
C.,^+^*.
J D LErl,
"^:-,uDrrr
namespace VehicleDataOnly
r
nublic -strins
sModel;
I / norn du modle
-- -"D
public string sManufacturer; | / non, du constructeur
public int nNum0fDoors; / I nombre de portes du vhicule
public int nNum0fWheels; I I nonbre de roues du vhicule
I
_,,L1.t^
PUUAIL
^1^^_
\_fd
.,1 -SS1
Urd
C'est
static
tt
//
1'utilisateur
Vehicle
myCar
= new Vehicle0;
// utilise
string s = Console.Readline{);
= s;
myCar. sModel
Console.Write("Nombre de portes
s = Console.Readline{) ;
= ");
= Convert.Tolnt32(s)
tonsole.l.Jrite("Nonbre de roues = ");
myCar.nNumOfDoors
s = Console.ReadlineO;
109
I |0
= Convert.ToInt32 (s) ;
affiche maintenant 1es rsultats
Console .1,{riteLine (" \nVotre vhicule est une r') ;
myCar.nNum0fl{hee1s
/l
/l
Console.Read0;
Vehi
c 1 e.
La dfinition d'une classe peut tre place avant ou aprs Ciassl. C'est
sans importance. Adoptez simplement un style, et gardez-le.
Le programme cre un objet myCar de la classe Vehicle, puis remplit
chacune de ces proprits en lisant ce qui est saisi au clavier par I'utilisateur. Il n'y a pas de vrification de la validit des donnes. Le programme
restitue alors l'cran, dans un format lgrement diffrent, les donnes
saisies par I'utilisateur.
Nombre de roues
une
lan
Appuyez
Distinguer
tableaux
= "Studebaker" ;
ee qui
suit est
sans
objet carT et que vous lui assignezle nom de constructeur "Hudson", a n'aura aucun effet sur la Studebakr carI
Si vous crez un
La capacit de distinguer les objets les uns des autres constitue une
partie de la puissance de la notion de classe. L'objet associ la 2 CV
Citron peut tre cr, manipul ou mme ignor, comme une entit
part entire, distincte des autres objets, y compris I'Avanti (bien que ce
soient toutes deux des classiques).
L'oprateur point et I'oprateur d'assignation sont les deux seuls oprateurs dfinis sur les types de rfrence :
I
Vehicle yourCar;
l/ assigne une valeur la rfrence
yourCar = new Vehicle0 I
yourCar. sManufacturer = "Rambler" ;
ll cre une nouvelle rfrence et 1a
Vehicle yourSpousalCar = yourCar;
fait
La premire ligne cre un objet yourCar sans lui assigner une valeur. On
dit qu'une rfrence qui n'a pas t initialise pointe vers I'o7et nu7l.
Toute tentative d'utiliser une rfrence non initialise produit une erreur
I I I
| |2
6${ea^
-!3\ Le compilateur
ler
:(d
W )
\/
rfrence non initialise met fin immdiatement
I'excution du programme.
Figure 6.1
..--yourcut\
La relation
entre deux
iii?i1:J, />tr"h'*l
l-....--l
"Rambler"
yourSpo usalCar-/
Y
L'excution de ce programme afficherait "Da5rtona", et non "Ford T". Remarquez que yourSp<rusalCar ne pointe pas vers yourCar. Au contraire, ce sont
les deux qui se rfrent au mme vhicule.
En outre, la rfrence yourSpousalCar serait encore valide, mme si la
variable yourCar tait d'une manire ou d'une autre "perdue" (se trouvait
hors de porte, par exemple) :
I ^11
'+rsJ11
Ir dPydrLrrIL
II I
vvLl
fenme
!uus
aussi q votre
duDf
IL
NULL"
le mme vhicule
Console.l^lriteLine("Votre voiture tait une " * yourSpousalCar.sModel)
yourSpousalCar rfrence toujours
frg)
;^ i-+
-1,.-nfDOOfS;
rllL
llllqltlv
;-+
rlrL
yu!ffL
^"L1.i^
-T'.^^f\nJheelS;
rrrrul[v
public
int
nrrhl
yuvlrL i^
lnrrhla
uvuua
nPower;
licnln.'pmpnt.
Urryrq!Lu!rrL,
I
I
//
//
//
//
I
non du modle
nan du constructeur
noinhrp d nortes du vhicule
nombre de roues du vhicule
puissance du moteur (Chevaux-Vapeur)
cylindre du moteur (litres)
Autrement clit, le moteur est une entit lui seul et mrite sa propre classe
class Motor
fI
n"hlin
yuVI rL
int
lll L nDnr.rar.
lMWq!
/i
n3
I I tl
/l
Vehicle
/
I
l/
II
I
non du mod1e
non du constructeur
nombre de portes du vhicule
lcr.ons d'abord un
objet de 1a classe
Motor
new Motor0;
largerMotor.nPower = 230:
t'lotor LargerMotor
largerMotor.displacenent = 4.0i
I I crons maintenant 1a voiture
"Cherokee Sport";
sonsCar. sManfacturer
"JeeP";
sonsCar.nNumberofDoors = 2 ;
sons0ar.number0fWheels = 4;
L'objet de la classe Vehicle vous offre deux moyens d'accder la cylindre de son moteur. Vous pouvez procder une tape la fois :
Motor m = sons0ar.notor;
Console,Writeline("La cylindre du noteur est
"*
m.displacenent);
"*
sonsCar.motor.displacernent);
;..
ffi
=,
tableaux
nlnc< (ler
//1e
numro d'
innatriculation
ner^r Car
slicensePlate =
"XYZ123'r
Mais il y a aussi des proprits partages par toutes les voitures. Par
exemple, le nombre total de voitures construites est une proprit de la
classe Car, et non de quelconque objet. Un tel membre d'une classe est
appel proprit de closse, et est identifi en C# par le mot static :
nrrhlin
nl.c< Crr
slicensePLate = "48C123" ;
incrnente le nombre de voitures pour
. nNurnbe r0fCars** ;
new0ar.
I
Car
| |5
| |6
class C1ass1
{
int
[]
nMaxTemperatures
for(int
index =
new
0; index (
int
[nDaysnYear]
nDayslnYear; index**)
I
.additionne la temprature naxinale pour
/l jour de 1'anne.
chaque
Les
tableauv : la classe
lfAn-,-r-,
r r d_y
Les variables qui ne contiennent qu'une seule valeur sont bien pratiques, et
les classes qui permettent de dcrire les objets composites sont cruciales.
Mais il vous faut aussi une structure capable de contenir un ensemble
d'objets de mme type. La classe intgre
'lr ra.,/ est une structure qui peut
contenir une srie d'lments de mme type (valeurs de type 1nt, double, et
ainsi de suite, ou alors obiets de la classe \iehi,---e, i{or-or:, et ainsi de suite).
double d0 = 5.
double dl = ),
double d2 = J.
double d3
double d4 = 5.
d0uble d) * R,
double d6 * I'
double d7 = Qr
double d8 = 1.
double d9 = f .
di + d8 + d9;
-$ttK La classe Array prsente une syntaxe spciale qui la rend plus facile
-f il ) utiliser. Les doubles crochets ll reprsentent Ia manire qui permet
Wt/
d0
d1
n7
I |8
1 d1,
Les nurnros cles lments du tableau (0, 1 ,2, eI ainsi de suite) constituent
l'index.
#i
e,
d'utiliser une variable comme index du tableau. Il est plus facile d'utiliser
f o r que de se rfrer manuellement chaque lment, comme
le montre le programme suivant :
une boucle
FixedArrayAverage
de valeurs en
utilisant
nombre dternin
une boucle
nanespace FixedArrayAvera ge
{
-^
'.^.1
urrr5
C,,^+^-.
uJ
LIr,
double[] dArray
f5
7
r,
? 5
JrJ
R 1
double
dSum
1
.,
?].
Jt
du tableau
0;
for(inti=0;i(11;i++)
{
dsum
dSun
-f dnrray[iJ
return
l
]
]
0;
rr).
calculatrice).
Et si vous dpassez la
taille du tableau
Sije n'avais itr que sur neuf lments, C# ne l'aurait pas considr comme une erreur : s
vous voulez lire neuf lments d'un tableau qui en contient dix, de quel droit C# viendrait-il le
contester ? Bien sr, la moyenne serait incorrecte, mais le programme n'aurait aucun moyen
de le savoir.
Etsij'avais itr suronze lments {ou plus} ? Maintenant, a regarde beaucoup C#.C#ne
vous permet pas d'indexer au-del de la taille d'un tableau, de crainte d'craser une valeur
importante dans la mmoire. Pour le vrifier, j'ai remplac le test de comparaison de la boucle
forpf cequisuit:for(int
i:0; i (
11; i++),enremplaant10par11.L'excution
Au premier abord, ce message d'erreur parat imposant, mais on peut facilement en saisir
l'essentiel : il s'est produit une erreur IndexOut0fRangeException. ll est clair que C#
indique que le programme a essay d'accder un tableau au-del de ses limites (le onzime
lmentd'un tableau qui n'en cornporte que dix). La suite du message indique la ligne exacte
laquelle s'est produite cette tentative d'accs, mais vous n'avez pas encore assez avanc
dans ce livre pour comprendre tout ce qu'il vous dit.
ng
Chapitre
6:
tableaux
for (int i = 0; i (
numElements; i++)
dValue;
double
dSum
": ");
valeurs
0;
for (int i = 0; i (
nunELements; i++)
dsum=dSum*dArrayliJ;
]
l,/rite (dAverage
* " est la
moyenne
+ dArray [o] )
for (int i = 1; i (
de ("
nuniElements; i++)
Console.l.IriteLine(") I u + numElements);
// attend confirmation de 1'utilisateur
Console,I,rlriteLine("Appuyez sur Entre pour terminer. ..")
Console.Read0;
return
0;
Voici un exemple de rsultats affichs, pour lequel j'ai entr cinq valeurs,
de I 5, dont la moyenne calcule par le programme est de 3 :
Nonbre de valeurs pour 1a moyenne
calculer
l2 |
tableaux
": ");
dValue;
8, 1, 9,
l,
3l;
Ici, j'ai utilis new pour allouer explicitement la mmoire, et j'ai fait suivre
cette dclaration par les valeurs initiales des membres du tableau.
123
tableaux | 2 5
lil
students
dCPn
dMyGPA;
I
I
I
I
AverageStudentGPA
- calcule
d'UV
(GPA)
("^+^-.
uJLrlrl
',^.i-^
urrr5
nanespace AverageStudentGPA
{
public class
Student
public string
nrrhlin
sName;
//
inrrh'l ^ dp[.
moyenne des
points
d'UV
]
n115S1
^..L1.: ^ Ufd
^1^^^ Urd
PUUATU
{
(s)
i++)
+(i+1)t":");
string
sName
= ConsoLe.Readline0;
thisstudent.
sName
sName;
: ");
,l^
F,ntrez.
s
DttLLL
luvjllrl
q mvn1
uE -^'i-+^
yvfrrL
Entrez 1e
n-+-^-
lllL!4
I rTTlt
. j,5
uv
de 1'tudiant 3: Carrie
de yvrrrLo
ooints d'UV
: 4.0
nlUJClI-lC
uL
u uv
nom
Appuyez
^$st
1^{t
t\7,
Y
c el nss Strrdent
{
nrrhl i n <trino
nrthli^
cT\^*^ '
uriOlltE,
rlflP'
rlnrrhla
//
movenne
l
n'!hlr^
PUUTTL
LrA
^t^dd
r'r^dr1
VrdD
I
I
.ere le tableau,
I
I et fait 1a moyenne des tudiants
double
= 0.0;
= 0; i ( students,Length;
for (int i
{
dSun
du tableau
dSum
*= students Ii]
.dgPn;
l
double dAvg = dsum/students.Length;
II
.utilise le tableau.
1fT
t27
I 28
La boucle
- o r-
-/ \
;/
-('^..L \ students. i,enpth contient le nombre d'lments du tableau.
a-;,,.":"" r,;r:,rr" o" contrle de flux, nomme roreach, spcialement conue pour I'itration dans un conteneur tel qu'un tableau. Elle
fonctionne de la faon suivante :
Ill t
^.:+
rcllL
double
l^
rd
*^,,^-^^
lruyetllte
dSum
^uej
tudiants du tableau
= 0.0;
dSun
*= stud.
double dAvg
dGPA;
dSur/students.Length;
U
oc$IQa"
frg)
du type Student.
Ghapitre
6:
tableaux I
studentsIi]
studentsIj]
/l
studentsljl = tenp;
Ici, la rfrence d'objet de I'emplacement i du tableau students est
sauvegard, afin qu'elle ne soit pas perdue lorsque la deuxime instruction change la valeur de students Ii] . Enfin, le contenu de la variable
temp est stock I'emplacement j. Dans une reprsentation visuelle, cette
opration ressemble la Figure 6.2.
Avant:
studentslil
studentsljl
Aprs:
Figure 6.2
"Permuter
deux objets'
-signifie en
ra lit
"permuter
deux
rfrences
au mme
objet".
29
130
nnsnctr SortStudents
t
class Class i
{
rrl
= Stuoeirt.NewStuIsn;("llagg-e", 3.5)
studentsl4i
// output the iist as is:
Console . ldriteline (r'A,rant de tr j-er : " ) ;
OutputStudentArray ( students ) ;
I I trie maintenant 1a liste des
I I du meilleur au pius nauvais
tudiants
Console.WriteLine("\nTri en ccurs\n")
Student. Sort (students)
l/
foreach(Student s
in
students)
i
Console.llriteline (s.GetString
l
l
]
i / Student class Student
{
-,.L1.i^
puD-r-LC
Lrrng sflame;
s^+-.i-^
^N
(nom
et rsultats)
return student;
l
I r'^+e*-)
^rvertit
Lf L en
crr Lrrdrlrc
chane 1'obiet
II I UsLLrarr
LUllvc!
Student
en cours
public string GetString0
I
{
a++-ia^
^:
Lrrrr
[il.
,
s *=
dGrade;
g f= tr - tr'
s f= sName;
return s;
]
/l
II
Sort
- trie
hnnl hRonontT.nnn.
// rnte 1a bouc'i c ittsntt' ne ntr4 1a liste soit trie
^
UU
|
I
studentsIindex + 1] ,dGrade)
t
i1s sont
permuts.
lindex]
from;
studentslindex + 1] = to;
II
. et f indj.cateur bRepeatloop dit si il faudra
I I f.aire encore un passage sur 1a liste des tudiants
I I (continue itrer jusqu' ce que tous les objets
tableaux |
3 |
32
I while (bRepeatloop);
j
0-
trier
Homer
2 - Bart
3 - Marge
3.5 - Maggie
Tri
en cours
Li.sa
3-
Marge
3.5 2
0-
Maggie
Bart
Honer
nnttt'ao
nyyuJL
o'rr
ur
Fn+r6a
lrrL!s
nnrrr
Pvu!
tarminar
LErluJllc!,,.
Chapitre
Homer
Lisa
Bart
-le tri en
Marge
bul I es.
Maggie
Figure 6.3
Avant de
c0mmencer
Figure 6.4
Aprs le
premier
-passage
du
tri en bulles.
Figure 6.5
Lisa
Bart
4
2
Marge
Maggie
3.5
Homer
O <-
Lisa 4 <:
Aprs le
deuxime
passage du
tri en bulles.
Marge
Maggie
3.5
Bart 2 <-
Lisa reste
tout en haut.
Homer A
Figure 6.6
Aprs
I'ava nt-
-dernier
Lisa
passage, la
liste est
E
_
) Maggie
4
Marge 3
Bart 2
trie. Le
passage final
met fin au tri
en constatant que rien
ne change.
Maooie
4
3.5
Homer A
133
|3
-gf{c
137 -^$: \,
=f ItU )
{t-l
Chapitre 7
36
h'rhl1^
yuvrrL
rh+
hln+,
()
L'lment ilr,- est r:r nTetnbre drntn(r. une clonne menrbre d une classe
(la classe E.',a.-r ;,;), comme nous en avons vu beaLlcoup au Chapitre 6,
mais l'lment I'j-.:r., r r F'-r .'- '.
est (l'Lrn qenre nouveau : c'est une
fonction membre (une fonction. menrbre cl'une classe). Une fonction est un
bloc de code C# clue volls pouvez excLlter en rfrenant son nom. Ce
sera plus clair avec Lln exemple (n'oubliez pas nos conventions, le nom
d'une classe commence par Llne majllscule : .,i::r.p ' er est un objet de la
,
classe Exan,nl e ).
rrn nhiot
ovrmnlo nTnt = l.
//un
membre donne
//utilise
Exanrple.nStaticlnt = 2i
//.,//un
1a classe pour
initialiser
*^-L-^
^++-.i
mernDre
srarlque
Exanple. ClassFunction
I ltttil
icp I'nhict
nnrrr inrrnnrtpr
classe |
Lorsquejeclcrisdesfonctions,jemetslesparenthsespourqu'elles
f >,1
llglf
soient plus faciles reconnaltre, sinon j'ai un peu de nral rn'y retrouver.
Ce petit morceau de code C# avec ses deux exemples cle fonctions ne fait rien
d'autre qu'afficher deux petites chalnes cle caractres sur la console, rnais urte
fonction effectue gnralement des oprations utiles et parfois cornplexes ; par
exemple calculer un sinus ou concatner cleux char-res cle caractres, otr
encore, envoyer subrepticement par rnail votre {.JI- Microsoft. Vous pouvez
faire des fonctictns aussi longues et compliques que vous votrlez.
ce n'est pas le cas, c'est que les commentaires sont mal faits.
Dans les grandes lignes, le programme Ca. cur atelnre res'-Tab i e apparalt
comme suit
//demande
initial
37
38
r
L
//olus I'intrt
/ /rf ti".i.r. 1es rsultats
lI
i
l
Si vous I'examinez avec un peu de recul, vous verrez que ce programme
t/
t/
t/
,/
Le principal.
t/
Le taux d'intrt.
tz
La dure.
I
I
II
II
II
I
CalculatelnterestTablel,lithFunctions
une
using Systen;
namespace
CalculatelnterestTablel,lithFunct ions
public class
C1ass1
decimal mPrincipal : 0;
decimal mlnterest = 0;
deci.mal mDuration
crer la table
0;
ref mPrincipal
ref mlnterest,
ref mDuration);
l/Section 2 - affiche les donnes pour vrification
Console.Writeline0; II skip aline
Console.IdriteLine("Principal = " *mPrincipal);
Console.llri.teline("Taux d'intrt = rr + nlnterest + "%");
= rr +mDuration+ " ans");
Console.Writeline("Dure
InputlnterestData
Console.I,Iriteli.ne
Console.ReadO;
l
- Ifr.i+L q !a!-"-tir
neina.l
/ Inoutlntere.+n.+.
Lv! v L!q Lq
L1!
IE!
1e y!nr.iarrulyal
f,tr
du LIAv
Uu
Clavier
II
les informati.ons sur le taux d'intrt
ll
et 1a dure, ncessaires pour calculer
II
la table des valeurs futures
/ / (CeUte fonction inrplmente la Section 1 en 1a divisant
i
,.
/ len Erots
conposanLs)
nrrhl'in stetin
rroid TnnrrtTntora<tlleiafrof
eoinel mPrinninal
ryqsq\!
I ta -
lecture du principal
//
II
dcimaL
et
de
classe | 39
| 40
sPrompt)
I(
eont
1'utilisateur entre
while (true)
I
t
I Lit
1'utilisateur
+ sPrompt * " : t') ;
string slnput :
i,f
(mValue
)=
0)
{-.
// retourne 1a valeur
return
mValue;
'I
I/ I/
l ^1 | ^--^..
-.i ^-^
^.i -^genere
^--^
pour slgnaler
Slnon,
un message ^^,,l'erreur
Console.\tlriteline(sPrompt * " doit avoir une valeur positive");
Console,l,{riteline ("Veui11ez reconnencer") ;
Console.lJriteline0;
l
J
.I
for (int
nYear
= 1;
//
II
decimal nlnterestPaid
* (mlnterest / 100);
// calcule naintenant 1e nouveau principal en ajoutant
/ I 7'intrt au prcdent principal
mPrincipal = nPrincipal t mlnterestPj.d;
I I arrondit 1e principal au centime 1e plus proche
mPrincipal : decinal Round (rnPrincipal , 2)
ll affiche 1e rsultat
Console.l,rlriteline(nYear + rt-ti * nPrincipal)
mlnterestPaid: mPrincipal
]
I
classe | 4 |
i(^$tlK
il )
\g)
partir de l.
C'est la mme logique de diviser pour rgner qui est l'uvre dans la
fonction InputlnterestData O. Vous pouvez vous y concentrer exclusivement sur la saisie des trois valeurs dcimales. Toutefois. dans ce cas. on
s'aperoit que la saisie de chaque valeur fait appel aux mmes oprations.
La fonction InputPositiveDecimal O rassemble ces oprations dans un
bloc de code que vous pouvez appliquer tout aussi bien au principal, au
taux d'intrt, et la dure.
Cette fonction TnputPositiveDecimal O affiche I'invite qu'elle a reue
lorsqu'elle a t invoque, et attend la saisie de I'utilisateur. Puis, si cette
valeur n'est pas ngative, elle la retourne au point o elle a t appele. Si
la valeur est ngative, la fonction affiche un message d'erreur et demande
nouveau la valeur I'utilisateur.
t42
Veuillez
recommencer
10
= 100
Principal
d'intrt = 10i,
Dure
= 10 ans
Taux
1-i10
2-tzL
3-i33.1
4-146,41
5-16i.05
6-171.16
7
- 194.88
8-
214 .37
9-235.8r
1A - 259
.39
Appuyez
Lorsque le langage F0RTRAN a introduit la notion de fonction dans les annes cinquante, le
seuf but en tait d'viter la duplication de code en rassemblant les portions identiques dans
un seul f ment commun. f maginez que vous ayez eu crire un programme devant calculer
et afficher des ratios en de nombreux endroits diffrents. Votre pr0gramme aurait pu appeler
itelile
classe | 43
lly a un autre avantage qui devient rapidement vident: il est plus facile d'crire correctementlecoded'unefonction.LafonctionDispl-ayRatloO vrifiequelednominateurn'est
pas nul. Sivous rptez le code du calcul en plusieurs endroits dans votre pr0gramme, il est
pour dterminer o placer les retours la ligne qui dterminent I'affichage du paragraphe.
talculatel,Iordwrap O elle-mme appellerait une fonction LookupwordBreak O pour
dciderdes ventuelles coupures de mots la fin des lignes. Comme vous le voyez, nous venons
de dcrire chacune de ces fonctions en une seule phrase simple.
Sans la possibilit de reprsenter des concepts complexes, il deviendrait presque impossible
d'crire des programmes de complexit simplement moyenne, a fortiori un systme d'exploi-
tation romme Windows XP, un utilitaire comme WinZip, un traitement de terte c0mrne
WordPerfect, ou encore un jeu comme StarFighter, pour ne citer que quelques exemples.
vnid 0rrtnrt o
|44
ob
jets
Comparez cet exemple aux vritables fonctions qui font waiment quelque
chose. Par exemple, I'opration de calcul d'un sinus ncessite une donne (il
faut bien que ce soit Ie sinus de quelque chose). De mme, pour concatner
deux chanes en une seule, il faut commencer par en avoir deux. Il faut passer
deux chalnes comme donnes la fonction Concatenate r ) . Il vous faut donc
un moyen de passer des donnes une fonction et de rcuprer ce qui en sort.
public class
Example
{
nrrhl
puurlLin
rrnir{
vuru
<f
af in
LeLfL
f\rrf
ntr* llctrin^
vuLyuL
\DL!rtl
"n^(+ri-^'l
tutrLJL!rir/
"
]
1
^rr
)
/
.
t
a reu I1|^-^.'*^-+
argumenr .;
U^l1
nel.Lo
string upperString =
Output (upperString)
"He11o";
classe I
Figure 7.1
L'invo cation
Out
put
- rnnorStri nc
fr
upperString
:r Jrr il r9 =-\
copie la
valeur de
rrnnor(t.i
nr
-rr. _" -_ _.,t
Output
\,/
Y/
------>
"Hello"
(funcString)/
da ns
frnntr:
nc
*rui3
,.r
+-l:,;\
I
tti
I
|
C'
,./
AverageAndDisplay
using
System;
namespace Exanple
t
//
Console.Read0;
l
I
I
/
AverageAndDisplay
- fait
leur
45
4aa
4O
* dl
ts2
*"etde"
* " dont 1a valeur est " t d2
* rr est gale " + dAverage);
La moyenne de UV 1 dont
nnlrroz
crrr
Fntr6o
nnrrr
UV
1'orm'inor
d,I
e3.5et4.0.
/l
',--l*^
uf lrB C,,^+^*.
)/ Lxl ,
namespace AverageWithComp
{
ilerError
n'c
ctasse | 47
ll
args)
3.5, 4.0)
/l
..")
Console.Read0;
l
I
I
|
AverageAndDisplay
- fait
leur
double dAverage
= (d1 + d2) I
2;
d1
*s2
*"etde"
* " dont 1a valeur est " * d2
* " est ga1e " + dAverage);
l
J
I
C# ne peut pas faire correspondre les arguments qui sont passs dans I'appel
AverageAndDisplay 0 avec la dfinition de la fonction. La chane "LJV 1"
correspond bien au premier argument qui est de type string dans la dfinition de la fonction, mais pour le deuxime, la dfinition de la fonction demande
un type double alors que c'est une chne qui est passe dans I'appel.
-f
Vous pouvez donner le mme nom deux fonctions d'une mme classe,
condition que leurs arguments soient diffrents. On appelle a surcharger
le nom de la fonction.
t48
I nvE!acnllu!f,yrqjvvrrvqu9u
ore
lltvlr--montr
LLLE
version
vsrDrvrr
a-^"^-^ ^^ ^-rn"r snl rvOverl o,adpd - cette
/ /
1r fnnntinn
rurr
Lfv!r
Arrpr:snn,1T1.i.^l
rrvu!u;CnllUUfyroJ
ro
o-'
Ave
rageAndDisplayOver loaded
njthltn
crec<
{ le.gg]
Console.Read0;
l
I
I
I
I
ArerageAndDisplay
d1,
d2)
doub:e dAverage
= (dl + d2) I
?.;
" T s1
* 'r dont 1a yaleur est " *
Console,WriteLine("La moyenne de
Console,lrlritel,ine("et de
d1);
+^1
"
a+^+.i
n
LALaL
double dAverase
: (Ci + d2) I
d2)
2:
" * d1
+d2
*"et"
* " est gale " + dAverage);
u'gelir,dDrsplay ().
Il invoque I'une puis I'autre en leur passant respectivement les arguments
qu'il leur faut. C# peut iclentifier la fonctit-rn (lemancle par le programrne en
Ce programme clfinit deux versi()n.s de la fonction r-,
classe I 49
r^ "^^ -^i-+^
^+ UC VU' PUrrlLb
L
r!o^ -^,,^--^
ruvJsrrlr
Annlt\to"
cltr
J'UV dont
ga1e
3,75
,1
I ( EL
t, cL
a^^1 ^ \ .3,75
^ JrJ
^+ T
^^t cdr
uc
Fntra
n^rrr tormlnr
comprendre.
.P\
"Qt ;:iffili,'il:i:ilJr'"iit
re
Une autre version de la mme fonction, bien qu'un peu fade, offrirait des
performances acceptables, en remplaant certains des arguments par des
valeurs par dfaut.
La surcharge d'un nom de fonction permet d'implmenter facilement des
valeurs par dfaut.
Examinez ces deux versions de la fonction L)i spl31-p.eundeCDecina i O
//
I
II
/
FunctionsWithDefaultArguments
| 50
using
System;
nanespac e FunctionsWithDefaultArormpnts
/l
Console
ll
3)
Console.Read0;
l
//
I
DisplayRoundedDecimal
tl
- convertit
mValue,
int nNunberOfSignifieantDigits
//
//
tt
commence pas
decinal
mRoundedValue =
dec
nNunb erOfS
//
Convertit en chalne
string s *
ignif ic antDigits
le rsultat
obtenu
Convert.?oString(rnRoundedValue)
reurn s;
]
mValue)
//
I
invoque DisplayRoundedDecimal(decinal,
int),
string s =
DisplayRoundedDecinal(mValue, 2)
return s;
l
l
]
*fR.''
=oi
Fournir des arguments par dfaut prsente plus d'intrt que d'pargner
simplement quelques efforts un programmeur paresseux. Les recherches inutiles dans la documentation pour y trouver Ia signification d'arguments qui sont normalement dfinis par dfaut distraient le programmeur
de sa tche principale et la lui rendent plus difficile, lui font perdre clu
temps, et augmentent le risque de produire des erreurs. Le programmeur
qui est I'auteur d'une fonction comprend les relations entre ses arguments. C'est lui que revient la charge d'en fournir une version simplifie,
plus facile utiliser.
hleur
#i
[o,
forme consiste
pctsser
par rfrence.
Les programmeurs ont leur manire de dire les choses. En parlant d'un type
valeur. quand un programmeur dit "passer une variable une for-rction", cela
signifie gnralement "passer une fonction la valeur d'une variable".
Passer
//
PassByValue
using
System;
namespace PassByValue
{
t5t
I5
ob
jets
I I Update
II
I
..
- essaie
de modifier 1a valeur
lui sort
passs
doubLe
C)
1 =
/t)'
d = 20.0:
l
public static void Main(string[] args)
t
I I dc|are
int i = 1;
deux variables
et 1es ini.ti-alise
double d = 2.0;
Console.WriteLine("Avant 1'appel 'Jpdate(int, double) :")
Console.Writeline(!'i - 'r + i + ", d = " * d);
/i invoque 1a fonction
Update(i, d);
Read
i = i, d = 2
Aprs 1'appe1 Update(int, double):
nnrrrroz
crrr
F'nfrave
nnrrl|orminor
rvu!
L'appel -Lipria"- () passe les valeurs I et 2.0, et non une rfrence aux
variables i et C. Aussi, Ia modification de ces valeurs I'intrieur de Ia
fonction n'a aucun effet sur Ia valeur des variables dans la rclutine appelant la fonction.
hleur
Il est avantageux de passer par rfrence une fonction un argumeltt d'un type
valeur, en particulier lorsque le programme appelant besoin de donner
Ghap itre
//
_-"-ffi
@t
PassByReference
C.,^+ ^*
JLc$,
,, ^.: - ^
urrr
namespace PassByReference
(
L
I
I
- essaie
de nrodifier 1a valeur
des argunents qui 1ui sont passs
public static void Update(ref int i, out double
I
I
Update
d)
i = l0;
d = 20.0;
]
deux vari.ables
et 1es initialise
double d I
Console.I,IriteLine("Avant 1'appe1 Update(ref int, out double):");
Console.ltlriteline(rri = r? + i + ", d n'est pas initialis");
// invoque 1a fonetion
Update(ref i, out d);
l-l renarquez que les valeurs 1 et 2.0 n'ont pas chang
Console.llriteline("Aprs 1'appel Update(ref int, out double) :") ;
Console.Writeline('ri - u * i + ", d = + d) ;
"
/i attend confirmation de 1'utilisateur
. . ")
uons0le.KeadlJ;
Le mot-cl ref indique que c'est une rfrence que C# doit passer i, et
non la valeur contenue dans cette variable. Il en rsulte que les modifications apportes cette valeur dans la fonction sont exportes dans le
programme qui I'appelle.
De faon similaire, le mot<l out dit "restituer par rfrence, mais peu m'importe
quelle tait la valeur initiale, puisque de toute faon je vais la remplacer" (a fait
53
I5
^--^r
L1 dPvL
^--:^
nyrs
d iinriate(ref
uyuoLs\rr
rrrLr
int. out
uuL uuuuItr,/,
double)
i = 10, d = 20
Appuyez
Ne passez pas une uariable par rfrence une fonction deux fois en
mme temps
Jamais, sous aucun prtexte, vous ne devez passer deux fois par rfrence
la mme variable dans un mme appel une fonction. La raison en est plus
difficile expliquer qu' montrer. Examinez la fonction Update O suivante :
//tt
^
PassByReferenceError
montre une
quand on
using
System;
namespce PassByReferenceBrror
{
Update
- essaie
de modifier la valeur
des arguments qui 1ui sont passs
int
nVar2)
nfar} = 20:
'I
et
1es
initialise
" I rrYqrr,/,
tr
I nvrlJ:
Chap itre
// invoque 1a fonction
DisplayAndUpdate(ref n, ref n);
// remarquez que 1es valeurs 1 et 2.0 n'ont
pas chang
Console.I,lritelineO;
Console.I,iriteLine("Aprs 1'appe1 Update(ref n, ref n):");
Console.Writeline('t1 = " * n) ;
// attend confirmation de 1'uti-lisareur
Console.WriteLine("Appuyez sur Entre pour terminer. ..") ;
Console.ReadO;
Update i r"i i:ri . ref in: ) est maintenant dclare pour accepter par
rfrence deux arguments de type in*-, ce qui, en soi, n'est pas un problme. Le problme se produit lorsque la fonction l"lain O invoque
Update O en lui passant la mme variable pour les deux arguments. Dans
la fonction, --ipiate ' t modifie rrruiar,, ce qui, par rfrence n, remplace
sa valeur initiale de I par la valeur 10. En mme temps, Upclate O mociifie
nVar2, alors que la valeur de n, laquelle elle se rfre, a dj t modifie en recevant la valeur 10.
Ce qui est mis en vidence dans I'exemple suivant
Avant 1'appe1 Update(ref
n, ref n):
n=1
La valeur
La valeur
10
n, ref n):
n=20
nnrrrran
nyyuJ4
df\
=(D
arrr
u!
Fnfpf,6
lltL!
nnttr
yvur
torm"inar
L!llrrrl!
t!
56
int
nVariable;
Mais C# ne peut pas assurer la surveillance des variables I'intrieur d'une fonction
Console
savoirsinVarlable
initialise avantd'tre
int
nUninitializedVariable
SorneFunet ion
ref
Si C# avait acce pt cet appel, SomeFunction ( ) se serait vu passer une rfrence une
variable non initialise {donc n'ayant aucun sens}. Le mot-cl out permet aux deux parties
de se mettre d'accord sur le fait qu'aucune valeur n'a encore t assigne la variable.
L'exemple suivant se compile sans problme :
int nljninitializedVariable
SomeFunction
(out nUninitializedVariable)
int nlnitializedVariable = 1;
SomeFunction
(out nTnitializedVariable)
LavafeurdenlnitiallzedlariableseracrasedansSomeFunctionO,maisiln'ya
aucun risque que soit passe une valeur dpourvue de sens.
Retourner une
classe I 57
hleur l'erltdteur
Dans bien des oprations clu monde rel, des valeurs sont cres pour tre
retournes ;\ celui clui les a envoyes. Par exemple, sir' i' I accepte un argument
pour lequel elle calcule la fonction trigonomtrique sinus, et retourne la valeur
corresponclante. Une fonction dispose de deux moyens pour retourner une
valeur celui qui I'a appele. La plus courante est I'utilisation clu champ
r err.l::i, mais ily a une autre mthode qui utilise l'appel par rfrence.
Utilser
une
hleur
Example
d2)
double dAverage
return
(d1 + d2)
z:
dAverage:
Test
double v1 = 1.0;
double v2 = 3.0;
double dAverageValue = Average(v1, v2);
Console.I,lriteline("La moyenne de 't { vl
1"etde"+v2*t'est"
* dAverageValue);
v1
I, vcrdctur,
^..::-i: ,'.',.,r v2));
]
]
I5
A9L\
"(o)
Dans ce cas, certains diraient que "la fonction retotrrne ,-,..,,'i :1!,:,". C'est
un abus de langage, mais un raccourc'i rl'usagc courant. Dire clur:
c,.'r,r-,r-r: ou t<lut autre variable est passe ou retourne r-r 11trr,: ce soit
n'a aucun sens. Dans ce cas, c'est la valc'ttr cotttetttte cians i ",r ,,.'.,flui
est retourne au programme appelant.
L'appel
-",
Une fonction qui retourne une valeur. c()nrme ', "' ,. . ne peut pas la
retourner en rencontrant la dernire lrarenthse fernrante de la fonction.
Si c'tait le cas, comrnent ferait C# pour savoir cprelle valeur retourner ?
t tt^)^+^
^^^^t^
uPuoLc - trDditr
It r
de nrodifier 1a valeur
des arguments qui 1ui sont passs
public static void Update(ref int i, out double
I
C)
f
!
d
rv
=
/t)
tt.
Quand utlser
public class
classe I
Example
dResults = (dt
]
nrrhf in ctatin
d2)
rrnid 'test
d2)
z;
()
double v1 = 1.0;
double v2 = 3.0;
double dAverageValue;
Average(dAverageValue,
v1,
v2)
v1
*ttetdett*v2*"est"
f dAverageValue;
C'est le plus souvent par I'instruction retur:n que vous allez retourner
une valeur au programme appelant, plutt que par la directive c,,1i:, bien
qu'il soit difficile de contester que a revient au mme.
rloubie ncessite
ogq{qa. Utiliser our- avec une variable d'un type valeur comme
un procd supplmentaire que I'on appelle boxing, dont la description
sort du cadre de ce livre. Toutefois, I'efficacit ne doit pas tre un facteur
cl dans votre choix.
frg)
Example
-+-+.:^,,.rid
^ LdLfU
-..L1.:
VU
PUUr,l-U
AverageAndProduct
dl,
double d2)
dAverage=(dl+62;
dProduct =
dl *
l2;
d2;
.r$9- 1
7X
tsfl,
Y
Une fonction qui retourne elle seule plusieurs valeurs est une crature
que I'on ne rencontre pas aussi souve;t qu'on pourrait le croire. Une telle
fonction est souvent encapsule dans un obiet de classe ou dans un
tableau de valeurs.
59
I 60
laleur
Il y a des fonctions qui ne retournent aucune valeur au programme appelant. Une fonction que nous avons utilise plus haut comme exemple,
AverageA:dDispia-r ( ), affiche la moyenne des arguments qui lui sont
passs, mais ne retourne pas cette moyenne au programme appelant. Ce
n'est peut-tre pas une bonne ide, mais telle n'est pas ici la question. Au
lieu de laisser en blanc le type retourn, une fonction comffle
A.rerap.eAndDi spla\.() est dclare de la faon suivante:
publi.c void AverageAndDisplay(double, double)
programme appelant.
{$a/
ft>ll
l/i7
-z
Une fonction qui ne retourne aucune valeur est appele une fonction sans
gpe (uoid function). Par opposition, une fonction qui retourne une valeur
est appele une fonction Upe (non-uoid function).
Une fonction type doit restituer le contrle au programme appelant par une
instruction rerurn suivie par la valeur retourner. Une fonction sans type
n'a aucune valeur retourner. Elle restitue le contrle lorsqu'elle rencontre
un retui n eui n'est suivi d'aucune valeur. Par dfaut, une fonction sans type
se termine automatiquement (restitue le contrle au programme appelant)
lorsque le contrle atteint I'accolade fermante qui en indique la fin.
Examinez la fonction
public class
li splayRatlo ( )
Exanple
^+^+.:^ .,^id
^"L1.:^ DL4LfL
yuurrL
DisplayRatio (double dNumerator,
vu
double dDenoninator)
t
si le
if
t
Console , WriteLine
I
classe | 6l
return:
l
I I ceci n'est excut que si dDenominator n'est pas
double dRatio = dNumerator / dDenominator;
nu1
*"sur"*dDenominator
* " est ea1 " * dRatio);
class
Example
int
nValue;
ll
null refl
Example
ref2.nValue = 0:
t62
variable ref 1 est peu prs aussivide que mon portefeuille. Elle pointe vers l'objetnull-.
c'est--dire vers aucun objet. En revanche, ref 2 pointe vers un obiet dont la valeur est 0.
La
string
-qtrino
s1;
? = trlr'
C'est essentiellement la mme chose: s1 pointe vers I'objet nu11, et s2 pointe vers une
chane vide, La diffrence est significative, comme fe montre la fonction suivante :
I
I Test -
nanespace
modules dp
test
norrr
lest
using Systeu;
puurr.c srarr.c
^+^+.i^
hrrL1.i^
int
..i-+
rt^il----:,
rl
Main(string
IJ strings)\
Console.l.IriteLine0;
Console.Writeline0;
ll
Irlriteline
attend confirmation de
ConsoLe.i,lriteline(,,Appuyez
-t
I
Console. nead
return 0;
()
l,utilisateur
sur Entre,pour terniner. . .,,)
nl acc
cfasse | 63
Fvamnl o
reurn:
J
'
gales).
Ce programme affiche les rsultats suivants
n^
*-^^*^-*^ "*r1ise
uLrlrE
la rvllL
1a
fonction
Lfulr TestStrinso
v yru6!nutrs
- -- -- -----o v
Passage
Passage d'une
.^
IEltrrtr
E rfr^
Appuyez
.
d..
vritable chaine
t+an1
LcL
qfrjnsl
u,!rlrb
t64
La question de Ma i ii
a un pr0qramme
Examinez toutes les applications console de ce livre. L'excution commence toujours par |1a,r, i r. Sa dclaration vc)Lls dit clairement de quoi il
s'agit
emplacement de
votre
args)
programme.
l'lair-' i t est une fonction statique ou une fclnctior-r de classe cle la classe
Class -. dfinie par I'Assistant Applications cle \risual Stuclio. ;.1-r ne
/l
DisplayArguments
affiche
au
srrr5
".{-^
1es arguments
qui sont
passs
programme
(rra+^m '
pJ
Lu,
namespace DisplayArgument
{
PsuIrL
Lr
rcL
//
Console.l,{riteLine("Ce programme
args . Length)
I I les arguments sont
int nCount = 0;
foreach(string arg in args)
:
a {0) arguments"
ncount#, arg)
]
I I attend confirmation de 1'utilisateur
Console.lrlriteLine("Appuyez sur Entre pour terminer'
"")
Console.ReadO;
return 0:
lc argl argZ
a 3 argunents
DisplayArgunents
Ce programne
L'argunent 0 est /c
L'argunent 1 est argl
Ltargument 2 est arg2
Appuyez sur Entre pour terminer...
wLaplupartdesapplicationSconSoleautorisentl'utilisationd'optionsqui
lLrrlrf
Y
l'nte de D0S
1.
t65
I 66
respectable antiquit C:
2.
\)
Prograinnes
C/.
L'invite devient
c : \ C/Programs
\nisplayArguments).
Figure7.2:
L'utilitaire de
recherc he
-de Windows
est une aide
prcieuse
p0ur
retrouver ses
f
ic h iers.
ctasse |
,;-;;,
-li:l
''
Adresse IlJ
Flultill,l
;
1..
)
fi:f
t't
{". ,']l
:!
Re(her.her
t{ Noveru
,"V
lI
i-rlr tr I ii l.f
U
Figure 7.3
lJ.
:r,t r,:r
Le voil !
Le nom du
dossier
apparat
droite du
nom du
f
ichier.
3.
L'invite devient
: \ ClPr c gr
ar,s'rtispla-,'Arguments \bin\,De:ug.
la Figure 7.4.
67
| 68
Figure 7.4
L'excution
de
Dlsplay
-Argunents
partir de
I invite du
D0S affiche
les arguments
que vous avez
passs au
programme.
lr;---;
I
i-r*n,i;;,*ntt
_)
t-t
[ro55rr
P,Fte de tra\.3i1
"&)
r-l-
F\t.rris iJEu
!,: -
Figure 7.5
Jirhrrre
drer:t iJl-[r,1
iJ
Ft!fJfr:.ll
trj,triL -'r
I ilr] t:t i'
+ J
|
- *l
. l.
lttl
+ I
[r:,:]rl:rrlj lrl iii
* _J ir,ar:t,rt
+
I Fr: tr.lr I tE!
_,.] Frt'tr :r'li;: ,--#
rt:
internt E:{plrr
Dans
Windows,
-vous p0uvez
excuter un
!j'."Dnarrr ,.]ullr,l
Elpfert
pr0gramme
console en
doublecliquant sur
le nom du
fichier
c0rresp0ndant.
|.7;\
;i
Fsvari: r:.eau
l:.:.|:'
Internet Er,k'rer
Figure 7.6:
Dans
:rt:'el
-l
lirrL,r';r,-fir'r
4,'.
Windows,
f,m3frtsr utlok
Elpress
VOUS OOUVEZ
faire olisser
et dposer un
fichier sur un
''
programme
consote pour
dclencher
iorbeille
s0n
execuuon.
i
-l
]i
c_!l
:rnl'l. rFr ::
[,t::Ft:i'ir
]u1f
|:5.i5r:t
r::E
ri'lr
classe
169
I 70
'--,
-.';
:,
' : Il
.,ri'r..- . :r,,,..
JJ
l4e5 dc,:umPrrls
Figure 7.7
Faire glisser
des fichiers
sur le nom
:
'l- FTf.drl
,-l
Adr5ri I
,l
)
l-r ,i
s:1
Pste d trd?il
d'un
programme
produit le
t+,
mme
l\.-.
rsultat que
si vous
l'aviez
excut
pa rtir de la
ligne de
lntrrr;t ExFlor?i
tk,
-'
Dmrrer 'Sutloal
ErFrBJ5
commande
en lui
passant les
noms des
- l
tsl
rlr :r,nl
oa''
. '1ii
Corbeille
tj],-l::,.1 ::
Etr:.t,I: r!,,n,t,,i: :::t:t
n)l'1i= rln,e-ii r::[f]ll::r
.tr:Fl:,'rt,rr enr', r.
li '
f -r:r,::i:
-s i :r:i ,rl!
-1.: ,.r:ri.l1 rr Nr:i!" r:
1r i l':rl a-,rl' ir,ri,:
+: :
fichiers
correspon
dants.
ste\
=(t
ot,iEtl
jl
5lilnnr,iJl
partir de Uisual
classe l7l
Par dfaut, c'est sans arguments que Visual Studio excute un programme.
Si ce n'est pas ce que vous voulez, vous devez indiquer Visual Studio les
arguments utiliser
l.
2.
J'
__1
Elasst.cs
. .-:
,*:.i
r,E.ur
r.i:1rl lllrstErr,
rr!u:'!-,f
! r.
!a -.
,,,1 I r,-
'1
i'r
:J
r j -aiLr.U1rrr-::
:.=-
T:=r
; t) , r - :'i'ri
lr.:
IIalr:i:',
1Lr._il]
::{:
ttr rr: :
hltTffi
iPtSujtgllit*.ilJJli]llr
+ _J Flrerr:i
'Li. lenettt
tj] A:serrl'lr Ir,f :.:
l'leferef
{l - :ss1.':::
Ajlrllei
1t1i
-pro prits
rril!rlnt
= tl:
i:,:i1:lr'siIllr:1
l,rrler un reiererrce'{tt,
[:eftrrr,:rJnrnrt t,rc]el
ill
EJJ
3.
Y. 1t'g
de,lerr;rt;le
let,lluf
-
.1r:f
d'un projet,
cliquez du
bouton droit
l:?l
Figure 7,8 :
Pour
accder aux
Help
- i$
@re
net
lW.
| 72
.+,l-
?f
I
t,isFl
-. -a q
Classt,cs
jet
Ge*rer
Qbcguer
aa
.'
Help
' ,:a"* :
L1trlrl
:)
!-0nfi,rurttiDn
F.h--rj-,tr-d'
Flate-forme
---:
8....
.,
tI-,i:,iF"
Figure 7,9
Dans le
champ
gutil! Feqh*
GestionnderonfiE:ratim:.,.
rl:,r.r
[]enr,rrt r l-lFL
F.rr lP d.,,r,,!,1P
A:F
A:,F.llET
Fil5E
':l:,rer e Jehr,tq
de la ligne de
,:tr/Ef l dEt,r!l,l,l
n:n
Fi
comma n0e
de la fentre
Pages de
rlr.'r l 'lEt'i,,t3tt
..,
a,
3ra,-tE
_ir
rer
Flse
s
F,l15
.l'
EtrG@EGIEE!E@/t'irlrlrrqil
FFerl:Ie J lfd'r]rl
T,:rllr:!rj rtlt]tSet InlfTl Erfr rlrE Ttita
proprits,
'Lr5Flni,Arqrrrnfrt5' l1 Frr,jel
,r:i;
-Arguments
entrez les
a rguments
du programme.
4 .X
.,..
'***!
, Fr;tr*
-.,r -a)
fr :olrt'on
1..,
,,
f tr- -l
Annul?r
,,
, I tit
Fl
4.
/c argl
en
slectionnant Dboguer/Dmarrer.
Comme le montre la Figure 7.10, Visual Studio ouvre une fentre
DOS avec les rsultats attendus :
Ce prograrnme
a3
arguments
L'argument 0 est lc
L'argument 1 est argl
L'argument 2 est arg}
Appuyez sur Entre pour terminer...
ttrtils
Feqte
Figure 7.10
classe | 73
Help
etu,1
Visual Studio
peut passer
-des argu-
ments une
pplication
console.
La fonction
Writ eline
()
| 74
string s =
"Sarh"
COnSOle,Writelin.i/'rTo -rennol1o
r'*
Writeline
lci, la chane "Sarah" est insre l'endroit o apparat le symbole {0}. Le zro se rfre au
premier argument qui suit la chane elle-mme. Le nombre entier 3 est insr l'endroit
marqu par{1}. Cette forme est plus efficace que I'exemple prcdent, car la concatnation
de chanes n'estpas une chose aussifacile qu'ilyparat. C'estunetche quiprend dutemps.
mais ilfaut bien que quelqu'un e fasse.
f
ll n'y aurait pas grand-chose d'autre en dire si c'tait l la seule diffrence. Mais cette
deuxime forme de t,vriteLine O offre galement diffrentes possibilits de contrle du
format de sortie. Je les dcrirai au Chapitre I.
Chapitre
Mthodes de classe
Dans ce chaptre :
Passer un objet une fonction.
.a-2
IIO
fonction
//
ll
Pass0bjecr
rrcino Sv<tom'
nmsDc PassOhr'ect
i
nrrl^rlic r. lnss Strrdent
{
pubiic string
sName;
l
nl.hlr^
yuurrL
t'-SS1
uf,d.
^ ^^n
Lad'
// dfinit
1e nom en
Console.ldriteLine("La premire
student, sName
OutputName
I
accdant directement
fois :")
= "Madeleine";
(student)
change 1e nom en
Console
SetName
(student, "l{i1la")
:"
OutputName(student);
// vuLPuLrrd.xrtr
^"+-"+T^-^ affiche le nom de 1'tudi"ant
public static void OutputName(Student student)
rI
est
{0} "
student. sNane)
/l SetName nrodifie le
non de
1'objet tudiant
sName)
student.sName
sNane;
l
l
Chapitre
I : Mthodes de classe
-^i
lurD.^
il
Pass0bj ectToMetnberFunction
utilise
dans
using
I'obiet
champs
t77
| 78
public class
Student
public string
/l
OutputNane
sliame;
t0J",
student.sNane);
// SetNanre modifie le
public static void
non de
1'objet
SetName(Student
student
student, string
sName)
student,sNane = sNane:
l
l
-..11.:
^1^-PUUITL^ LrA
Classl
trMdeleine";
fonction
Console.l,lriteline("Aprs avoir t nodifi :")
Student.SetName(student, "l.Jil1a")
Student . OutputName ( student )
]
l
classe elle-mme la rend plus rutilisable : une fonction extrieure qui aura
t'Madeleine"
*-f,*i3
l----Hi';'f
trY"Y/
//
InvokeMethod
using Systen;
namespace InvokeMethod
{
class Student
t
| | te nom de 1'tudiant dcrit 1'objet student
pubLic string sFirstName;
t79
I80
sFirstNane
slastName
:
:
jets
sFNane,
string
slName)
sFNane;
slNane:
//
II
ob
ToNameString
student
string s = sFirstNane
tr rr + slastName;
return s;
)
* studenr.ToNaneStringO
// attend confirniation de 1'utili"sateur
Console,Read0;
l
1
vu plus haut. Cette fonction utilise des fonctions non statiques pour
manipuler un prnom et un nom.
Le programme commence par crer un nouvel objet, sti-rdent, de la classe
Student. Il invoque ensuite la fonction SetName O, qui stocke les deux
chalnes "Stephen" et "Davis" dans les membres donne sFirstlJane et
sLastl'Iarne. Enfin, le programme appelle la fonction membre
TolJameSt rlng ( ) , qui retourne le nom complet de student
concatnant les deux chanes.
Pour des raisons historiques qui n'ont rien voir avec C#, une fonction
membre non statique est communment appele une ntthode. J'utilise le
terme ntthode pour une fonction membre non statique, et le terme
fonction pour toutes les autres fonctions.
Regardez nouveau la fonction Setf,lame O qui met jour le nom et le
prnom dans un objet de la classe Student. Quel objet modifie
Setl{arne
"Jones")
christa.
:712
lfdll
lL-r^t
\Zl
sont pas censes avoir besoin. C'est un peu comme la manire dont nous utilisons les
boutons d'un four micro-ondes : ces boutons masguent le fonctionnement interne de
l'appareil, que nous n'avons pas besoin de connatre.
Le second rle d'une mthode est de reprsenter les proprits vritables de la classe. Un
avion peut acclrer, virer, dcof ler et atterrir (entre autres choses). Une classe Al rplane
| 8l
| 82
nrrhl i
n cl ess
Pprson
Console.
l^lriteline ( "Hi" ;
l
nrrhl
i,.
r.
l:ss T,etter
string
sAddress;
//rnet de ct 1'adresse
publi.c void Address(string
sNewAddress)
sAddress
= sNevAddress;
l
l
pas l, il est vident que le nom Sfep hen se rfre moi. Mais de retour dans
les bureaux, si vous appelez le nom "Stephen", c'est ambigu car il peut se
rfrer n'importe lequel de nous trois. Il vous faudra donc appeler "Stephen
Davis" pour viter Ia confusion avec "Stephen Williams" ou "Stephen Leija".
AP\
\tt
=l ,,1
-t'
\
I
Le nom de la classe est un autre moyen de diffrencier cles nom.s cle mthode
surchargs, les autres tant les noms et le nombre de ses arguments de
tonctron.
Student
llle
nom de
jn ctrinc
nrrhl
L!rrr
yuurrL
.in
nrrh'l
yuUlaL
//
!t!DLL\dUlY,
clrinc
L!ilr
SetName
^T^a+trI^-^.
IrL.lIdllltj'
met de ct
le
non de 1'tudiant
sFName,
string
slName)
sFirstName = sFNane;
slastName = slNane;
l
l
l
]
studentl
SetNane
("Joseph"
, "Snith") ;
I 83
|84
Je ne suis pas en train de dire que vous pouvez invoquer SetNane O de deux
manires diffrentes, mais simplement que les deux appels sont quivalents
d'un point de vue smantique. L'objet qui se trouve juste gauche de "." (le
premier argument cach) est pass la fonction tout comme les autres
arguments.
Passer un objet implicitement est facile avaler, mais que diriez-vous
d'une rfrence d'une mthode une autre ?
public class Student
t
ntrhli^
c*riro
cE'ir! r"ctNrmo'
D Llrell
PUVTTL L! f rr r
-,.1^1.i
^T
^
^+-.:-^
^^+[1^-^.
LtArr
!ALrrdrl,
PUUaJL
slastNarne)
SetFirstName ( sFirstName)
SetlastName ( slastName) ;
sName)
sFirstNane =
sNane i
sName)
slastNane =
sName;
l
]
Qu'est-ce que
this
.)
Contrairement la plupart des arguments, toutefois, I'objet courant n'apparat pas dans Ia liste des arguments de la fonction et ne se voit donc pas
assigner un nom par le programmeur. Au lieu de cela, C# assigne cet objet
le nom this.
Ghapitre
#\
=(d
8: Mthodes de classe
Student
t
yswLLw
^,,L1i^
ntrhl in
yss4+s
a+r.i-^
aD"i *-+1^*^.
o u. rrr$ sFirstNarne
nT aa+1\T^n^.
rei-rinc'
L. rrri !d.
Lllclllle ,
slastName)
sName)
this.sFirstName =
l
public void
SetlastNane
this.
sName;
slastName
(string
sNane)
sName;
Quand
.)
1l
Address
class
- dfinit
Person
public string
sName;
USA
| 85
| 86
yuuf
rL
nrrhli^
yu!arL
rll
rltu
r'n'izl
vvlu
Tni+(o1r'i
IllaL
\L!arr6 1g
s1\ame,
r-nr ntu/
.
Yh\
t
L
this.
sName
this . nID =
sName;
nID
conment
n'i t lrr - n
nr
montre
-- riogramme
utiliser explicitement 1a rfrence this
'i
rrs'ino Svctpm'
namespace Ref erenc ingTh j.sExplic
itly
public class
C1ass1
Console. ItlriteLine
.
510tog1e tu1"/;
student.Enro11 ("Biologie 101")
/laffichage des cours auxquels est inscrit 1'tudiant
Console.Iljriteline("Nouve11es caractristiques de 1'tudiant :")
!^'rr\
student. DisplayCourse
//
Console.
Console.ReadO;
return
0;
..")
Chapitre
I : Mthodes de classe | 87
sName;
nID;
this.sNane =
sName;
this.nID : nID;
courselnstance = nul1;
]
cours
Init (this ,
courselnstance.
sCourseID)
courselnstance.Display ( ) ;
l
//
II
Courselnstance
n^,.rselnstance
-..L1.r^
^1 ^^- VVU
PUUTTL LID
{
Display - affiche f
public void Display0
//
intitul
Console.l,lriteline (sCourseID)
l
l
tt
du cours
sCourseID)
| 88
un tudiant trs occup). l,lain ( ) cre l'tudiant, puis invoque lnit I ) pour
initiali.ser I'objet de la classe Str-iCent. ce point, la rfrence corjf sLrf ristance
reoit la valeur nui 1, car l'tudiant ne s'est pas encore inscrit au cours.
this I
Mlanger des fonctions de classe et des rnthodes d'objet, c'est un peu cornme
de mlanger des cow-boys et les propritaires de ranch. Heureusement, C#
vous donne quelque moyen de contourner les problmes relationnels de ces
cratures. a me rappelle un peu la chanson d'Oklahornct!: "Oh, la fonction et
la mthode peuvent tre amies..."
//
II
l'tixingfunctionsAndl'lethods
C,,^+^*.
y
Lctrl,
',^i-^
ufrr6
t
nrrb'1
ic
cl ass Strrdent
student
slastName)
I/
OutputBanner affiche
introduction
Console.I,rIritel,ine("Regardez comme
Ghapitre 8:Mthodes de
classe
public void
OutputBannerAndNarre
()
(this
//
Outputnane
Console.l.]riteLine
student . ToNameStrins
))
// ToNaneString - va chercher 1e
n,rhl i n ctri-1g ToNameString 0
nom
de 1'tudiant
ll ici, le non de 1'objet courant est implicite // ce qui. aurait pu tre crit
// return this.sFirstName + rt tr * thi-s.slastNane;
return sFirstName + tr n * slastNane:
:
]
]
public class
C1ass1
Console.TiritelineO;
// affi.che nouveau 1a bannire et 1e
nom
student . OutputBannerAndName i ) ;
I I attend confirnation de 1'utilisateur
Console.llriteLine("Appuyez sur Entre pour terminer... ")
Console.
Read
l
]
I
189
| 90
par
Lrr r
cet appel.
La fonctioo 0utpul-Banner (I voudrait peut-tre pouvoir appeler aussi
ToNameString O, mais elle n'a pas d'objet de la classe Str-rdent utiliser.
Elle n'a pas de pointeur tfiis parce que c'est une fonction statique et
qu'aucun objet ne lui a t pass explicitement.
Une fonction statique ne peut pas appeler une mthode non statique sans
lui passer explicitement un objet. Pas d'objet, pas d'appel.
- la saise
Visual Studio .NET comporte une fonction de saisie automatique extrmement utile au programmeur. Lorsque vous tapez le nom d'une classe ou
d'un objet dans votre code source, Visual Studio utilise les premiers
caractres que vous tapez pour anticiper la suite et vous proposer un
choix de noms parmi lesquels se trouve celui que vous voulez saisir.
Ghapitre
I : Mthodes de classe
programme Mixi
ngFrrn c t, i on s Andi'lethod s
Console.I,Triteline0;
I I af.fiche nouveau
la bannire et 1e nom
student . OutputBannerAndName ( ) ;
Figure 8.1
La
fonction
de saisie
-automatique
de Visual
Studio est
une aide
prcieuse
pour choisir
la bonne
r
:it llrlE 851 ,-rrf
r:
,l
"' n"rd
:,ti:r,t i Ftldlrrr
tti-=,:' Q F f rrr-eE,l!Jl5
C :letErr':t
O:,eLIn
e ili 'rl
Q'.\rit:.:
Entr.:
t rlr 1llf
. ''
I
r
I
T
-&
mthode.
t9t
| 92
Schier
E-ditron
14,tt,.
-'lr
-+
&*&q4
r,ebu,,l
)rplorteur dE scdulfrns - t4ixin..,
lt!llr:,rn,tF:nttr'rr:nlt4elh:,l5., lii:1
Figure 8.2
$e{p
1&.-
tr _
"|'
Elassl.cs+
Efqjt
a"
;l
:l
tlr,trn,i:trn,'t[] ar't:t
{:J
$
-
Ji
5,rlrrl:rr'r'll irr'tFrrr:i.,rsAr'llrElh:,15
VixinqfunctronAndMethods
La fonction
de saisie
-utomatiq ue
a
affiche aussi
la liste des
arguments
. I j I I - .'rrl ir'rs:le
pour la
version de
votre choix
'JlrtrteLirr
istring format,
t,.3f.jnt5
,tt,je':f[] :rl1l
de la
fonction
\,,rriteline
(1.
-rtC
-.($-:-
lsz//
-
Vous n'avez donc pas besoin de taper le nom de la fonction. Imaginez que
vous ayez tap Writel pour identifier exactement la mthode voulue. En
voyant le nom iir:iteLine slectionn dans la liste, il vous suffit de taper
une parenthse ouvrante pour que Visual Studio complte automatiquement ce nom pour vous, aprs quoi, il vous restera taper les paramtres
que vous voulez passer, et la parenthse fermante.
Pour faire apparaltre la description des arguments de la version de
',,iriteline 0 que vous cherchez, cliquez sur I'une des flches dans I'infobulle qui apparalt lorsque vous tapez la parenthse ouvrante. Dans cette
info-bulle, la description du premier argument que vous avez saisir
apparalt en gras, comme le montre la Figure 8.2.
Aussitt que j'ai entr la chalne "chane", et une virgule. Visual Studio met
en gras la description du prochain argument saisir, comme le montre la
Figure 8.3.
rtcnter
toriln
l--, ,,, .
..' + 4,
'l'-,
t'
'
lrr,1e!
&
ii4:{
,ii.t
rl-lw
flasst.cs*
{fFichage
'
"&'&
'P -
1*:
oetu!
Erploraleur ,je ,:lutions -
l"liin.,. +
.v.
;l
Figure 8.3
Help
l.& -
Cr,t:in strrnll;r,1:i
:J
L
:J
.F HixrnqFun{tionf AndMethods
+ :j e|eferari
1l] ::enblrlrri:'::
.j! al551 rs
A chaque
tape, Visual
-Studio
affiche en
gras la
desc ription
du prochain
argument
l^ I lE 1'l - ,/,r I ' ,rfsirl rriillLr.e lilrrrrl ir,fiill:, prdnrs obiect[] argl
:- rl,-lrl.t .._]. Irl-L:ltrr.pr.i_rr,-l].J:illt I ;
saisir.
Ds que vous tapez la virgule qui suit un argument aprs I'avoir saisi, Visual
Studio affiche en gras dans I'info-bulle la description du prochain argument
saisir. Bien
| 93
t94
" .::'
Pfrlel
$nrer
*7*
Qeboguer
Qutils
Fe1he
Help
,"6 "& -
,tr
v, tel:tt_t
EaplorterJr desdulirn:: -
;i
ll:rnsrrrr':[]
:,;:'
:J
*j
,:l
)*"
lL'li{rr.,.
4 rl
rE
lrrilLE:
1ll :;errl,l,'irri: ::
r_!l d;s:1,cr
arlt:
-l:'
:Li::-
Figure 8.4
La saisle
automatique
est galement
disponible
1,r,1rl
9
4
eEl,lfir, rr;
DOUT VOS
pr0pres
^r\|'
,-f,
t\\vl
\z
E,tr:ij
,lHi::l-',ri
,.eL fr
ir t;t uleri
/::Lt:ll,llriE
S li,fjtrn:,1:rrr,l
e T,t5lrrr,l
,a
Ces icnes sont faciles reconnaltre. Celle d'un membre donne est en
bleu clair. celle d'une mthode est en violet et prcde de trois traits
horizontaux.
Dans la fentre, il y a des mthodes que je ne reconnais pas. Ce sont des
mthodes de base que reoivent d'office tous les objets. Dans ce groupe de
^qa/
I/}il
tSZt
Y
Encore une fois, il vous suffit alors de taper une parenthse ouvrante
pour que le nom de la mthode, pralablement mis en surbrillance dans
la liste. soit automatiquement complt.
Cette aide marche aussi pour les fonctions. Lorsque j'entre le nom de
classe S:,ident suivi par un point, Visual Studio affiche la liste des
membres de SruCent. Si je tape ensuite OutputN, Visual Studio affiche
I'info-bulle contenant la liste des arguments de Outputllan.e | ), comme le
montre la Figure 8.5.
Ghapitre 8: Mthodes de
n hiet
Editin
':.:,..
4a:,,
;t,
',J':"1 :
,t,+J
flassl.cs*
I
Figure 8.5
'-l ls:r
-{
-t
!;il}:
I'rrif i :.i:t ii
de saisie
a
E) ,liil.3lpur
'le sDlrjhns -
Mr{n,,, 4
La fonction
- utom atiq
classe |
de Visual
Studio donne
bea ucoup
aL!{;rl
ir,rr-rr 1 E,uu1.
:i i
( ur:ie
i,,utt,ult8ar,r,er
ll'ttulea
i,'
trt
Jerlf
mthodes
d'o bjet
comme pour
les fonctions
de classe.
Visual Studio ne peut fournir qu'une aicle limite pour les fonctions et les
classes cres par I'utilisateur. Par exemple, il ne sait pas ce que fait la
mthode Or,itpurlJame O. Heureusement, Visual Studio vous offre un
moyen dtourn de dire la fonction de saisie automatique ce que fait la
fonction, et mme un peu plus.
Pour indiquer une ligne de commentaire normal, vous utilisez deux barres
obliques : / /. Mais Visual Studio comprend aussi comme un commentaire
spcial ce qui est indiqu par trois barres obliques : I I I . Un tel commentaire
de documentotion permet de donner Visual Studio des informations supplmentaires, utilisables par la fonction de saisie automatique.
95
t96
1t$!Qa^ Pour tre honnte, c'est le langage Java qui a introduit cette ide.
Java
S%H\ dispose d'un programme supplmentaire capable d'extraire les commen=\J\y J taires marqus par ces trois barres obliques pour les rassembler dans un
Y'/ fichier de documentation spar. C# a apport une amlioration cette
innovation : I'aide en cours cl'dition.
Un commentaire de clocumentation petrt contenir n'importe quelle
combinaison des contmandes montres par le Tableau 8.1.
Signification
ry>
<returns></returns>
or$lQa^ Vous disposez de bien d'autres balises XML. Pour en savoir plus leur
sujet, consultez I'aide en ligne de Visual Studio (plus officiellement connue
sous le nom de MSDN pour Visual Studio) en slectionnant ?/lndex, et tapez
"XML" dans le champ Rechercher.
4i7q \
'Qg,
//
II
I'li"xi.ngFunctionsAndMethods
mthodes
using
System;
namespace MixingFunctionsAndMethods
{
lll
II
ktnnary)
sinple description d'un tudiant
I 26
thisStudent.dGPA = dGPA;
ll ajoute 1'objet Student au tableau
studentsli] = thisStudent;
]
I
for (int i = 0; i (
students.Length; i++)
dSum
*=
students
Ii]
dGPA;
]
rlnrrhlo
uvuure
Tarnfh.
dAtro
unv6 = /(116/o+rr,.lanfa
u!ud/ LUUstlLD,!slrLrl
/ 1 nrrtnrrt
fho
error age
--
Console.l{riteline0
* students.Length
* " tudiants est " + dAvg);
l/ attend confirmation de lrutilisateur
Console.Read0;
correctement dimensionn.
Le programme entre maintenant dans une boucle for initiale qui va lui
permettre de remplir le tableau. L'utilisateur se voit demander le nombre
et la moyenne des UV de chaque tudiant, I'un aprs I'autre. Ces donnes
le
nombre
d'tudiants
t24
^,.L1i^
puDi_r_c
^+-..i-^
^I\l
srrlng sr\ane;
public double
dGPA;
//
moyenne
num
Studenl[] students =
gs\
e,
S/
/-.)
nerr/ St.udentfnu:rl;
for (int i = 0; i (
students,Length; i++)
students[i] =
new Students0;
t22
Entrez 1a valeur
ne5
3 est 1a noyenne de (1 + 2 + 3 + 4 + 5)
Appuyez
Enfin, la section finale affiche le rsultat du calcul, avec les valeurs qui
ont t entres, dans une prsentation agrable lire.
U
^dK
:(dw
\/
La proprit
fength
for (int i = 0; i (
numElennts; iff")
| 20
Le tableau
longueur uarable
Un programme qui pourrait lire un nombre variable de valeurs, ventuellement dtermines par I'utilisateur au cours de I'excution, serait beaucoup plus souple. Il fonctionnerait non seulement pour les dix valeurs
spcifies dans FixedArrayAverage, mais aussi pour n'importe quel autre
ensemble de valeurs.
La dclaration d'un tableau de longueur variable diffre lgrement de
celle d'un tableau de longueur fixe et valeurs fixes :
double[] dArray :
N
new double[N];
I
I
II
II
II
II
II
namespace VariableArrayAverage
l
using Systen;
public class Classl
t
-.,L1.i^
puorr.c ^+-+
args)
//
II
commence
que
par
lire
(sNumElements)
calculer
: ");
Chapitre
I : Mthodes de classe I 97
(lsunnary)
ll/
uublic class
Student
| | / (orr-^orrr).
II
\/UrUrtrdrj/
IJ IllI 1l^.,**^-.,\
oublic strins
/l
slastName;
lnitStudent
I I | (<,rmmrrrr\
l
/
/ n,.+-,,+n
LPU Llclllls!
I M
(orr^ rr.r)
lll
lll
II
affi.che f introduction
(lswnary)
nrrhf i n ctati
n 1ri 11 a)lltnlrtRennor
s usrrr.!
()
\ /
0utnrrtBannerAndNane
lll
lll
nrrh l
Gunnary)
lll <l*r*m"rrr)
i
//
e voi
11
0rrtnutBannerAndNane
non de
p<t nnss
rrtnrrtRannpr f l '
/ / I 'nhict
ll
//
le
'l
t98
ilt
/l affiche la bannire et le
0
Student. OutputBanner
string s =
nom
Student.0utputNanre(student,
5);
Console.I^IriteLine0;
// affiche nouveau
1a bannire
student . OutputBannerAndName ( ) ;
I
et
1e
nom
Console
il\,
Console,Read
1. Visual Studio
nnref
EE80n
i:'; ;.,::,.. t
ffiirha,1e
;,:!?
it.l
tlassl,c;*
/lt"t
|
1.
Piet
"..
enrer
&*&
Qbrguer
n&. /6
Sutili Fettre
'tr -
:tt't:t
Lebu'l
-.:srl
| tt:lnstrrnl[]arqsi
:l
pr0gramme
XML,
de bien
mieux
E,rurls
C
E
uLF|JLEnrnr
FeiErEn,:Eluls
dcrire la
fonction
et ses
a rguments.
,t
IJ
-document
EN
/s,rmnrar_y'),
Eeh
Avec un
Visual Studio
est capable
'
-J
:J
Figure 8.6
l:
199
200
2.
Une fois que j'ai saisi ou slectionn Ie nom cle la fonction, Vi.sual
Studio affiche une description clu prernier paramtre, extraite dtr
champ (par an)( lpa,,;rm), ainsi clue sorr type.
3.
^"tFJk
=Qg,
Cette section est trs technique. Si vous ne savez pas ce qu'est un fichier
XML, tout cela ne vous dira pas grancl-chose. Si vous savez comment est
fait un fichier XML, vous allez trouver cette fonction trs utile.
Slectionnez Affichage/Explorateur de solutions pour afficher I'Explorateur
de solutions. Dans I'Explorateur de solutions, cliquez clu bouton droit sur le
norl du prograrnme, et slectionnez Proprits. Dans le volet cle gauche de
la fentre Pages de proprits, cliquez sur le dossier Prcprits de
configuration 1:our I'ouvrir, et slectionnez Gnrer clans les pages clui
apparaissent au-dessous de ce dossier. Dans la section Sortie clu volet
de droite de la fentre Pages de proprits, slectionnez la proprit
nontme Ficli-ier de clocumt:ntatiorr XML. Dans la cellule qui se trouve
clroite de ce norn, entrez un nom de fichier. Comme je n'avais pas de
meilleure ide. j'ai mis xn-Loul-pu1 . xml. Clicluez sur OK pour applicluer
cette modification et fermer la fentre Pages de proprits.
:$uv
\'1
tZX
It9r,
L-,{t
I
-
,-t
-.
str
que tout a
Regarclez dans le mme dossier que le fichier source ul asg I . cs (le fichier
du projet est dans le mme clossier). Le nouveau fichier xrnl,rrrtf,r-Lt. rrni
dcrit toutes les fonctions clocurlentes par les balises XML.
Chapitre
Tordre une chalne et tirer dessus - mais vous ne pouvez pas la pousser.
Analyser une chalne lue par le programme.
Mettre en forme manuellement une chalne de sortie.
Mettre en forme une chalne de sortie en utilisant la mthode
;r ring
. Fo
ra:
,,
int i - i;
string s = "abc"
/i
II
string
202
Dans cet exemple, s-rl est dclar en tant qu'objet de la classe )^rring
(avec un 5 tnajr-tscule), alors que s2 est clclar en tant que variable cle
type s trr rrg (avec un.s minuscule). Mais ces deux assignatiorls montrent
que str j rg et :i tr ing sont de mme type (autrernent dit, compatibles).
.t9!I{0?r
7^H\
=(,l\y /
\/
En fait, cette proprit est galernent vraie pour les autres types de
variable, mais clans Lrne mesure plus limite. Mme le type int- possde sa
classe corresponclante, Ir,t,l2, douf-,ie correspond la classe t-)oub1e, et
ainsi cle suite. La cliffrence est que ritrirrg et String, sont rellement une
seule et mme chose.
t'Randy"
^IT^-^
rrr r\d.r*c
sNarne);
,.
^
^
II I| -.MotifrrS+rinn
nar la claSSe
I
II
II
ll
I
qui a t convertj.e)
'.^.i-^
uarr
C.'^+^!jLslu,
'
namespace Example
i
LfdS
urdnl
I
t
ll
objet student
si = new Student0;
s1. sName = "Jenny";
I I cre maintenant un nouvel objet
ct.e un
Student
= sl.
avec
le
nme nom
sName;
s2.sNarne
s1. sName.ToUpperO
Console.ReadO;
'I
ll Student class
Student
I(
public String
sName;
l
]
Les objets Str-Lcli-rt :r, et s2 sont dfinis de telle manire que leur membre
donne sfJarae pointe vers la mme chalne. L'appel la mthode
ToUpper ( ) convertit la chalne s l. sr'lane pour la mettre entirernent en
majuscules. Normalement, cela devrait poser un problme, car s I et s 2
pointent tous deux vers le meme objet, mais TcLIi per ( ) ne modifie pas
sName : elle cre une nouvelle chalne er] maiuscules.
203
204
sl'Jenny
Appuyez
s2 -
JENNY
19!llQp" L'invariabilit des chalnes est galentent importante pour les constantes de
7^[ \
V /
\-l
=(f
i ng. Une cirane conlrne "c]eci est une chalne" est une forme cle
constante cle type ::t r iirg. tout cornme I est une constante cle type j nt. De la
tnlne matrire clrre je rre jette pas mes chemises aprs usage pour rcluire le
volume cle ma garde-robe, un cornpilateur peut choisir de combiner tou.s les
accs la mrne constatrte "ceci est une c:ha1ne". Le principe cle rutilisation
d'une constartte cle type chalne permet cle rcluire la taille cl'un prograrnrle,
mais il serait irnpossible si un objet de type:;rring pouvait tre moclifi.
type
s Lr
tl
retourne
tl
.Si
retourne
t/
1.
-1.
retourne
0.
si, string
s2)
comme
des nombres)
return I
ll lous
si
1a chane
s1
return
return
-1
return
Ainsi, "abcd" est plus grand que "abbd", et "abcde" est plus grand que
"abcd". Vous n'aurez pas besoin tous les jours de savoir si une chane est
plus grande qu'une autre, mais il vous arrivera d'avoir besoin de savoir si
deux chalnes sont gales.
La- L-|ffi
r I r,in
ffil|
-
t
ll
ll
II
II
suivant construit
using
System;
namespac
e BuildASentence
I
L
publi.c class
C1ass1
205
206
for(;;)
t
I I Lit 1a saisie suivante
Console.Writeline("Entrez une chane") ;
string sLine = Console.ReadLine0;
ll sort de 1a boucle si c'est une chane de
if (IsTerminateString (sLine) )
fin
break;
]
sSentence
, . ")
Console.Read0;
"QIJTT"
r
It
qUit,, l
foreach(string sTerm
in
sTerms)
/1 retourn true si
if
return true;
)
return false;
Aprs avoir demand I'utilisateur de saisir la prernire ligne, le programme cr une chalne initiale vide nomme sSentence, puis il entre
dans une boucle "infinie".
Chapitre
b'
Par convention, le nom d'une fonction qui teste une proprit et retourne
true ou f aise doit commencer par Is. Dans notre exemple, le nom de la
fonction I sTerminateString ( ) signifie la question : "sLine est-elle une
chalne de fin ?" Bien str, ce n'est l qu'une convention humaine. Elle ne
sline n'est pas I'une des chalnes de fin, elle est concatne avec la
partie de la phrase dj saisie, au moyen de la fonction St ring . Cciic a:
Le programme affiche immdiatement le rsultat, afin que I'utilisateur
sache o il en est.
Si
()
4f\
=)
:t\vl
.a
jL'itrationSuruntableauestuntrsbonmoyendetestersiunevariable
ff-^l
lforl
l-t
207
208
taL^^..^
1-j^-^
.:, ..-^
^..^
^.i^..+i^
rrrc
vudguc
voUS entfez Sera ajoUte
Une
Ad
ohrase iusou' np attp vntts pntriez EXIT ou QUIT
Entrez une chane
Progranner avec C#
vu
Vous avez
entr :
Progranrner avec
C/l
Programmer avec
C1,
qw4r
, crest
amusant
Vous avez
entr :
c'est
amusant
(plus ou
Vous avez
uroins)
moins)
Phrrso
nnmnT
tp
Programner avec
Annrrrroz
v!
[yHeJ
crrr
F'nfro
nnnr
forminar
et "exit" comme cles chalnes diffrentes. Mais il existe une autre version
surcharge de cette fonction qui comporte un troisime argument. Celui-ci
indique si la comparaison doit ou non faire la diffrence entre les majuscules
et les minuscules. L'argument Lr ue indique d'ignorer Ia diffrence.
//
ll est
nrrhl'in
sOurCe)
quit,
sans
tenir
conpte
is
equal
Chapitre
Cette versicln d - ::1r'i,,'ir l i.,,,, e.1r l'- .,;, i est plus sirnple que la prcclente
qui utilisait une boucle. Elle n'a pas be.soin de se proccuper cles majuscules
et des minuscules. et elle peut utiliser une seule instruction conditionnelle,
!r
Et s je tleux utlser
-l-
a- '-i
bW-L
L
ch
.)
Pour tester si une chalne est gale une valeur particulire. vous pouvez
aussi utiliser la structure :;-",,;ri-,ri , r.
51}qS.
( il )
\U /
sT-ollilaie:,-. r irr-
r..'
//
II
source)
switch ( source
case I'EXfT":
c
as
e ttexit
^a^
Lqc
"
il^ITT11||.
qurr
case t'quit":
return true;
]
return false:
]
l
Cette approche fonctionne parce que vous ne comparezici qu'un nombre
limit de chalnes. Une boucle f or O offre un moyen beaucoup plus souple
de rechercher des valeurs de type chalne. La version de Compare () qui
ignore la distinction entre majuscules et minuscules donne au programme
une plus grande souplesse.
209
2l 0
L'analyse des caractres que contient une chalne est aussi un sujet que je
n'aime pas voquer, cle crainte que les programmeurs n'abusent de cette
technique. Il arrive que les programmeurs aillent un peu trop vite sauter
sur une chalne avant qu'elle soit entirement saisie pour en extraire ce
qu'ils y trouvent. C'est particulirement vrai des programmeurs f ++, cr
jusqu' I'introduction d'une classe de chalnes, c'tait la seule manire
dont ils pouvaient manipuler les chanes.
5lttrS, Bien str, une chalne n'est pas simplement un tableau cle caractres. Si on
i( il ) n" peut lire une chalne qu'un caractre la fois, on ne peut pas l'crire de
\ ln ./ la mme manire.
L'exemple sirnple clu programme St r in
de cette technique
gToCh
rAc
ces
s montre l'utilisation
lt
^
StrlngloUnarAccess
using Systen;
namespace StringToCharAccess
{
I r .
I
^l
public
class
Classl
t
L
1 .l
^..L
^ srar:-c
^+^+-i
^ voj.d Main(string[] args)
puDl:.c
t
I
I lit
:" f
sRandon);
:"
Console.Write(c);
]
suite de caractres
for(int i = 0; i (
sRandom.Length; i++)
tr
Votre saisie
conme
: au hasard)
Votre saisie affiche en utilisant foreach : Stephen Davj.s est un beau garon
Votre saisie affiche en utilisant for : Stephen Davis est un beau garon
sur Enrre pour terminer...
Appuyez
2n
2I2
ll
sRandom
= sRandon.Trin0
Bien que ce soit une fonction membre, Strrng. Tri n O retourne une
nouvelle chalne. La version prcdente de la chalne avec les caractres
imprimables en surnombre est perdue et ne peut plus tre utilise.
string s = Console.Readline0;
(s)
Atry(
=(\r'r
^'
\?_/
\/
de
la
chane
sRar^r)
return false;
l
//
for(int
i
chane
return false;
l
l
I
nombre
return true:
l
non
que
rien,
c'est
imprimable aux deux extrmits de la chalne. S'il ne reste
la chalne est vide et ne peut pas etre un entier. Puis, la fonction passe en
boucle sur chaque caractre de la chane. Si I'un de ces caractres n'est
pas un chiffre, la fonction retourne f a1se, indiquant que la chalne n'est
sans doute pas un nombre. Si cette fonction retourne true, il y a les plus
grandes chances que la chane puisse tre convertie en un type entier.
La fonction
lsAllIJrsrrs(
.
o$'ARGFf,
$'l, t- T__^1
La.
t]
!!t rsAllDigits
t-t1 1ni-ir -
using
).
1!^-- dmonstration
de 1a mthode IsAllDigits
Systemt
namespace Exanple
t
class Classl
{
public static
{
int Main(string[]
args)
2|3
2I4
if
(!
IsAllnigits
(s)
!");
]
e1s e
{
return
0;
\/
Le programnre suivant utilise Sp,r+ ,..) pour saisir une suite de nombres
additionner
,\#"Ti3
ffi..1
ttlI
II
II
nombres
nanespac
e ParseSequencelllithSplit
using
class
System;
C1ass1
public static
int
Main(string[1 args)
//
derrande
Console
I lit
):
une
ligne de texte
segments)
I
if
ll
if
{
(IsAllDieits
s)
2l 5
2I6
*=
num;
// affiche 1a somne
= {0}", nSun) ;
I attend confirmation de 1'utilisateur
Console.WriteLine("Sonne
I
return
Read
..")
0;
caractres
return false;
l
que 1a chane
return false;
l
]
I
rt1trr)
l-rt1.
7J,A
Q'
Nouveau
Nouveau
Nouveau
Nouveau
Sonme
Appuyez
nombre
nonbre =
nonbre =
nonbre =
1
2
10
-a
HDansunprogrammedestinunusagevritable,vousnevoudreZSanS
l[Orf
Y
doute pas ignorer une donne incorrecte sans rien signaler I'utilisateur.
PaC ( )
2t7
2 |8
'odsg9
,,1{J\,-
|[-T''?
l*
//
justifie
Ali8n0urput
la sortie
du programme
{
,'-.i-^
urrr5
Q.'a+a*
9JLclu,
'
class C1ass1
{
strinsil
Y_
+..b
!J
nanes
= ["Christa ",
t' Sarah" ,
"Jonathan"
,rsant,,
foreach(string s in
Liff ranfocrr).
Lvu
/
vr!
'
nanes)
Console
I^lriteline ( ) ;
aient toute la
pt sl'ion6oq
Console..|,trriteline("Voici 1es
foreach(string s
mmes noms"
in
sAlignedNames)
Console.
Writeline (
"Ceci est
..")
Console.Read0;
return
0;
//
I
|/
II
lrim.qndPad
espaces chaque
extrnit,
puis
//
|
l/
//
conrrence
chaque
for(int i = 0; i ( stringsToAlign.Length;
i++)
if (s.Length )
nMaxlength)
nMaxlength = s. Length;
l
stringsToAlign
Ii]
stringsToAiign[i] .PadRight(nMaxlength + l)
l
//
return stringsToAlign
]
2|I
220
Voici les
Ceci
Ceci
Ceci
Ceci
Ceci
est le
est
est
est
est
nom
le nom
1e nom
1e nom
le nom
'Christa
'Sarah
'Jonathan
'Sam
'
'
'
'
'Hildegarde '
la
aprs
aprs
aprs
aprs
aprs
TrimAndPad O retourne le tableau des chalnes allges de leurs caractres non imprimables droite et gauche par Trim O , et mis la bonne
longueur, du bot"t ct, par PadRight O. Main 0 effectue une itration sur
cette liste pour afficher I'une aprs I'autre toutes les chanes.
vqrlbe
cf rino
L!rrl
Rpnttin<fl'
a.Replace(s, ",'l')
,,"ctla
L*- I].
nanespace RemoveWhiteSpace
using
System;
public class
C1ass1
nrrhlin
cfafi6 i.nt
int Main(stringIJ
Main(strins['l strings]
strinss)
yuurrL o,o,ic
t
blancs
22 |
222
RemoveSpeci"al0hars
(s,
cWhiteSpace) )
Console.Read0;
return
0;
//
I
nrhl
jn
RemovpSnpcialChnrs
char
[]
cTargets)
for(;;)
{
boucle
break;
]
bLrlil
I
//
'
l
rt11rn crrinttt,
l
]
Chapitre
G#
-1.
Le programme Femo-,,ei,ihir,eSpar
chane
une
chane
aprs : ceciestunechane
Annrtrroz crrr Fntro nnrrr tormi ner
ll,lettre
concatnation
Le programme F.er,c-".e1,;'hitespacr donne un exemple d'utilisation cles
mthodes Concat O et IndexOf (), mais il n'emprunte pas lavoie laplus
efficace. Comme d'habitude, un bref examen rvle une solution lrlus
- supprine
KenoveSpeclalunars
cherfl r.Taropts)
{
<l-rino
// effectue
la division
223
22 t,
return sOutput;
l
String.Format("{0}
fois {l}
ga1e 12}"
, 2, 3, 2*3);
Il en rsulte la chalne
Contrle
C
- monnaie
Rsultat
Exemple
{0:C} avec
123,456
123,45
String.Format O.
Notes
Le symbole montaire dpend du
paramtrage de localisation, de mme
que I'usage de la virgule ou du point
comme sparateur de la paftie
dcimale.
{0:C} avec
D
E
-123,456
(123,45
F)
00123
- dcimal {0:D5} avec 123
- exponentiel {0:E) avec 123,45 1,2345E+02
{0:F2} avec 123,4567 123,45
- fixe
- nombre
{0:N}
Entiers seulement.
Oue l'on appelle aussi "notation
scientifique".
Le nombre qui suit le F indique le nombre
de chiffres aprs la virgule.
123456,789
123
456,19
123456.789
123
456,8
{0:N1}
457
X
OxFF
- hexadcimal {0:X}
012,30
{0:000.00} 12,3
{0:0...}
{0:###.##}12,3 12,3
{0:#...}
{0:N0}
123456.789
123
ldem.
0xFF est gal 255.
{0:##n.0#}
0,0
celui-ci est
{0:# or
0%}
{0:#00.#%l
,1234
12,3%
le signe %).
{0:#00.#%]10234
02,3o/o
0.
225
226
a
{Jlrtn11th'rm,atn^-+-^1
vuLyuLrv!llraLvvrlL!vr
t/ t
I
II
^ - ^^er^+
yrnrL
1'UtiliSateUr de redfinir 1e fornat
des nonbres saisis en utilisant l'excution
divers codes de contrle de format
nanespace OutputFornatControls
t
using
System;
public class
C1ass1
| . ' I
\ r , /
1^r
rv!
//
I
II
commence
string
if
sNumber
Console.Readline0
(sNumber.Length
0)
break;
I
J
stringl]
sFormats
"
/l
foreach(string s in sormats)
t
if
(s.Length !=
0)
{
I
entrs
try
{
Console.
I'lriteline
(sFormatConnand, dNumber)
l
catch (Exception)
{
.l,lriteline 0
Console.Read0;
return
0;
liriteline
sFo rmatComnand
dNumbe r )
dNumber)
227
228
c E F1 N0
La
espace
0000000.00000
commande
commande
La
commande
IZ
346
espace
00.0%
donne
L2,3',i,
exemple un
[J\f
(- ) Chapitre 15.
0uatrime partie
La programmation
oriente obiet
I'avoir
Chapitre 10
La programmation oriente
Abstraction et classification.
Comprendre I'importance de la programmation oriente objet.
232
trouvent sur la face avant. Quelques minutes plus tard, les nachos sont
prts.
Maintenant, pensez tout ce que je ne fais pas pour utiliser le four
micro-ondes:
t/
avant avec tous ses boutons et I'affichage de I'heure) qui me permet de faire tout ce dont i'ai besoin.
t/
t/
? 233
Lorsque je fais cela, on dit que je travaille (et que je pense) au niveau des
objets de base. ll me faut penser faire un four utile, mais ce stade je
n'ai pas encore rflchir au processus logique de la prparation des
nachos. Aprs tout, les concepteurs du four micro-ondes n'ont pas
pens spcifiquement ma manire de me prparer des nachos. Ils se
sont plutt consacrs rsoudre le problme de la conception et de la
fabrication d'un four micro-ondes utile.
Une fois que j'ai cod et test les objets dont j'ai besoin, je peux monter au
23 4
Les rponses donnes par mon fils dans mon exemple viennent de ce qu'il
sait de notre four micro-ondes, cas particulier du type d'objet appel
four micro-oncles. D'autre part, mon fils considre un four micro-ondes
comme un four d'un type particulier, et un four en gnral comrne un
appareil mnager d'un type particulier.
Dans la langue de la programmation oriente objet, mon four micro<rndes
est une instonce de la classe Four micro-oncles. l-a classe Four microondes
est une sousclasse de la classe Four. et la classe Four est une sous<lasse de la
classe Appareil mnager.
L'tre humain aime classifier. Tout ce qui peuple notre rnonde est ordonn en taxonomies. Ce procd nous pernret de rduire le nombre de
choses que nous avons retenir. Pensez par exemple la premire fois
que vous avez vu une "spacecar". La publicit la dcrivait probablernent
comme rvolutionnaire ("vous ne verrez plus jamais I'automobile de la
mme manire"). Et il est vrai que c'tait une nouveaut, mais aprs tout
une spacecar n'est rien d'autre qu'une voiture. En tant que telle, elle
partage toutes ses proprits (ou au moir-rs la plupart) avec les autres
voitures. Elle a un volant, des siges, un moteur, des freins, et ainsi de
suite. Je peux en conduire une sans commencer par lire le mode d'emploi.
Je n'ai pas besoin de m'encombrer la mmoire avec la liste de
tout ce
qu'une spacecar partage avec les autres voitures. Tout ce que j'ai
retenir est "une spacecar est une voiture qui...", t les quelques proprits qui sont propres aux spacecars (par exemple, le prix). Mais je peux
aller plus loin. La classe Voiture est une sous-classe de la classe Vhicules
roues, laquelle contient d'autres rnembres, coffrme les camions et les
dcapotables. Et la classe Vhicules roues peut tre une sous-classe de
la classe Vhicule, qui contient les bateaux et les avions. Et ainsi de suite,
aussi loin que vous voulez.
? 235
.)
besoin que de ce qu'il fait. Puis, j'introcluis dans le processus les instrtrctions
qui permettent de le faire fonctionner : "Mettre les nachos clans la Llolte
connecter le fil rouge au fil noir ; mettre le tube raclar sous tension cle
3 000 volts ; entendre le petit bruit qui indique le drnarrage ; ne pas s'approcher trop prs si on a I'intention d'avclir des enfant.s." Ce genre de choses.
;
t/
Trop complique : Je ne veux pas mlanger les cltaiis cle la fabrication d'un four micro-ondes avec ceux cle la prparation cles
nachos. Si je ne peux pas dfinir les objets et les extraire de cette
montagne de dtails pour les utiliser de faon indpendante, je suis
oblig de prendre en compte tous les dtails de tous les aspects du
problme en mme temps.
t/
tz
236
Chapitre
l0:
La pr0grammation oriente
tz
,/
Toutefois, pour que ces deux rgles soient respectes, vous avez aussi
votre part de responsabilit : vous ne pouvez f,aire aucune modification
I'intrieur de I'appareil.
Presque tous les appareils mnagers, de n'importe quel niveau de
complexit, notamment les fours micro-ondes, comportent un petit
sceau qui empche le consommateur d'accder leurs composants
internes. Si le sceau est bris, la responsabilit du fabricant n'est plus
engage. Si je modifie les composants internes d'un four, c'est moi qui
suis responsable s'il met le feu la maison.
De mme, une classe doit permettre de contrler I'accs ses membres.
237
238
objet:
t/
t/
responsable
Dans ce chapitre :
Permettre une classe de se protger par le contrle d'accs.
Permettre un objet de s'initialiser lui-mme par le constructeur.
Pour tre tenue responsable de ses actions, une classe doit avoir la
garantie que son tat initial est correct, et pouvoir contrler ses tats
suivants afin qu'ils le restent. C'est ce que permet C#.
240
registre sur lequel il me suffirait d'inscrire ce que j'ai pris dans Ia pile ou
ce que j'y ai ajout. Aprs tout, je pourrais trs bien oublier d'inscrire mes
retraits dans le registre. Je ne suis plus si jeune. Ma mmoire baisse.
Le contrle d'accs permet d'viter les petites erreurs comme d'oublier
d'inscrire un retrait ici ou l. Il pernret au.ssi cl'viter de vritables grosses
erreurs avec les retraits.
Je sais exactement ce que pensent ceux qui ont I'esprit fonctionr-rel : "ll
suffit de clfinir une rgle selon laquelle les autres classes ne peuvent pas
Un exemple yrublic de
public
BairkAc c ount
i/
II
II
II
II
BankAccount
en
(conserve
au
extrieur)
C"^+^*.
9J
D L!r,
u9rrr6
"^i-^
nanespce DoubleBankAccount
{
nrrhra^
yuurru
t'^SS1
vl
Lra
^rdd
ba. InitBankAccount
//on peut
I
//
membres donne
ba.Deposit(10);
// 1'accs direct un menbre donne provoque une erreur
ll Ia
conpilation
t= 10
// attend confirmation de 1'utilisateur
ba. dBalanee
ll
Banknccount
nrrhl
{
ie class
- dfinit
une classe
siurple
BankAccount
et un solde de 0
II
puDllc vo10 rnr.tbanxAccoun , \/\
nAccountNumber = **nNextAccountNumber
dBalance = 0.0;
//
GetBalance
- retourne 1e solde
courant
return
dBalance;
//
AccountNumber
public
int
GetAccountNumber0
return
nAccountNunber
nAccountNumber)
this.nAccountNumber = nAccountNumber
l
I/ I/ n^-^^'r+
r,/trPUlL
LUUL dnt
uyuL nositif
- +^!it
PvorLr!
est
autoris
dAmount)
if
(dAnount
0.0)
dBalance
*=
dAmount;
//
I!
Withdrar,{
24
242
(dBalance (= dWithdrawal)
if
{
dWithdrawal = dBalance;
l
dBalance -= dWithdrawal
return dWithdrawal;
/i
GetStrins
-- *..
-_,-
GetBalance 0 )
ratll
rn
]
]
suivant
'DoubleBankAccount.BankAccount.dBalancer
niveau de protection.
problme.
{q./
n)il
lS/
Y
=(t
fry\
Cette section suppose quelques notions sur l'hritage (Chapitre 12) et les
espaces de noms (Chapitre 16). Vous pouvez I'ignorer pour le moment,
mais vous Saurez qu'elle est l lorsque vous en aurez besoin.
C# offre d'autres niveaux de scurit, au-del de
public et private
t/
Un membre
t/
,/
,/
t/
Un membre
internal protected
laquelle il est dclar et toutes ses sous-classes, ainsi que par les
classes du mme module.
43
244
dclaratiort d'un rnembre comme i.nternal le rend disponible uniquement dans ce module. Mais si vous utilisez un seul espace de nom pour
tous vos modules, il n'y aura gure de diffrence entre une dclaration
irrternai ou irrl,ernal proreirteci et une dclaration public.
Dclarer les mernbres internes d'une classe comme public est une
mauvaise ide. au moins pour les raisons suivantes :
trs difficile.
t/
t/
Qu'arrive-t-il lorsque la banque dcide de modifier les rgles pour que les
"clients privilgis" soient autoriss avoir un solde lgrement ngatif
245
246
//
||
II
II
II
DoubleBankAccount
en
utilisant
une variable
nqnocn:no
extrieur)
Toct
using Systen;
nrrhlie class Classl
{
I I solde du conrpte
Console.l,lriteLine ("Compte : {0i",
ba.GetString0 );
\
I
I et voil le problrre
\s:'su4
ba.GetString0);
ll
return
0:
rr
I'
Ajout de 0,00 F
Compte rsultant
nnrrrraz
nPyuJ
arrr
u!
1'n+ro
lltL!cc
#tOOt
nnrrr
PUur
123,45
torm.inor
L!urllcr.
programme
//
II
Dec
lrnalBankAccount suivant
DecimalBankAccount
en
utilisant
une
ttsino Svstom'
nanespace
Dec
irralBankAccount
public class
C1ass1
-,,r"1.i^
void
VUaU
LdLrL
PUUafL ^+^+)^
Main(stringil
rlclrlr\LrrrrlJ
dL>l
args)
ba. InitBankAccount ( )
effectue un dpt
//
de
{0 : Ci "
dDeposit)
247
2 48
ll
= {01 ",
ba.GetStringO);
// et maj.ntenant, ajout d'un trs petit nontant
double dAddition : 0.002;
Console.l,lriteLine("Ajout de i0:CJ", dAddition)
Console.WriteLine("Compte
ba. Deposit
(dAddition)
I solde rsultant
Console,I^lriteLine("Compte rsultant
: [0]",
ba.GetString0):
//
BankRccount
public class
- dfinit
une classe
simple
BankAccount
//
private decimal
I
1000;
nBalance;
-.,1"
yuuf
fllrLUo
r^ i*!rnkACcoUnt 0
^ ,.^:
vvru
rL
nAccountNunber = **nNextAccountNumber
mBalance = 0;
GetBalance
return
(double)nBalance
//
AccountNumber
public
int
GetAccountNumber
return nAccountNumber
l
public void SetAccountNumber(int
;
nAccountNumber)
this . nAccountNumber =
nAccountNumber
if
(dAnount
0.0)
esr autoris
dAmount)
numro de compte
//
//
decimal
mTemp
mTemp
avnt
(decimal)dAmount;
= Decimal,Round(mTerrp, 2);
mBalance += nTenp;
]
//
II
Wi"thdrar,v
dWithdrar,val)
if
(mBalance
dWithdrawal
(= dWithdrawal)
mBalance;
mBalance -= dllithdrawal;
return dl^lithdrawal ;
c.)mnte
string s = String.Format("lf{Ol =
{1:C1",
GetAccountNunber ( )
GetBalance 0 ) ;
rtlrrn
a.
]
J
J'ai converti toutes les reprsentations internes en valeur dec rnat, qui
est dans tous les cas un type mieux adapt que dcubl au traitement de
solde de compte bancaire. La mthode Deposit (,r utilise maintenant la
fonction Decimal. Found O pour arrondir Ie montant des dpts au
centime le plus proche avant d'effectuer le dpt correspondant. La
sortie de ce programme est maintenant ce que nous sommes en droit
d'attendre
= r23,45 E
2 49
50
ob
jet
Et alors )
On pourrait toujours dire que j'aurais d crire ds le dpart le programme
BankAccount en utilisant le type decimal pour les donnes saisies, et je serais
probablement cl'accord. Mais ce n'est pas si vident. Bien des applications ont
t crites en utilisant le type double comme moyen de stockage. Un problme
s'est produit, mais la classe EankAccor-rnt tait capable de le rsoudre de faon
interne sans ncessiter de modifications I'application elle.mme.
#\
=O,
n,;iilL::.'"""u
1)
int
AccountNumber
La section get est implmente chaque fois que la proprit est lue, alors
que la section set est invoque lors de l'criture. La proprit Balance cidessous est en lecture seule, car seule la section set est dfinie :
public double
Balance
o1
t
return
(double)mBalance
l
]
//
ba.AccountNumber
I
new BankAccount
1001
Console.writeLine("lf[0] = {l :c}",
ba.AccountNumber, ba.Balance)
membres donne publics, par leur prsentation comme par leur utilisation. Toutefois, les proprits permettent la classe de protger ses
membres internes (tsa1ance est une proprit en lecture seule) et de
masquer leur implmentation. Remarquez que Balance effectue une
conversion. Elle aurait pu aussi excuter les calculs les plus abondants.
<$-_--
xParconvention(cen'estpaSuneobligationdeC#),lenomd'uneproprit
Ilof
l
L-.t
Proprits staques
Un membre donne statique (de classe) peut tre expos par I'intermdiaire d'une proprit statique, comme le montre I'exemple simple suivant
public class
I
BankAccount
5I
252
1000;
get
{return
nNextAecountNunber
il
]
I
I
I
int
AccountNumber
I
la proprit et prpare
I "*rr^it
I'extraction de la suivante
get
return
**nNextAccountNumber
dmarrer les choses, mais que se passe-t-il si I'application oublie d'appeler la fonction ? La classe commence avec de mauvaises initialisations,
et la situation ne peut pas s'amliorer ensuite. Si vous voulez tenir la
classe pour responsable de ce qu'elle fait, vous devez commencer par
lui assurer un bon dmarrage.
C# rsout le problme en appelant la fonction d'initialisation pour vous.
Par exemple
MyObject mo
new My0bject0;
int
n;
double d;
double dCalculatedValue = n
d:
C# sait que ni n ni d n'ont reu une valeur, et ne leur permet pas d'tre
utilises dans I'expression. La compilation de ce petit programme gnre
les erreurs de compilation suivantes :
t-lll
tdt
53
25
Q*a+^*
J)
^^
Llt,
'
namespace DecimalBankAccount
{
Maj_n(string
[]
args)
== null)
(
L
l
I
Read
l
l
public class
MyObject
internal int n;
internal MyObject next0bject
l
l
Ce programme
1oca10bject,n est
f1^^^1^L.'^^+
vLorvuJ EL L . -^--t0hipct
ilE - _ _ J _ _
Annttrroz qttr Entro
nnrrr
p<t
nrr'1
forminor
Lorsque I'objet est cr, C# excute ur-r petit morceau de code pour
I'initialiser, ainsi que ses membres. Livrs eux-mlnes, les membres
donne,.\:i.,'l:r,ject.i-, et le-xtr-;L e.i ne contienclraient que de.s valellrs
alatoires. sans signification.
Le code qui initialise les objets lorsqu'ils sont crs s'appelle le constructeur.
public class
BankAccount
int
nAecountNumber;
double dBalance;
IL
autres
membres
BankAccount ba
l
public class
= new BankAccount O ;
BankAccount
II
/i
static int
augmentent
nNextAccountNunber = 1000:
'l p
nrrmrn rlo nnmnf o at 'l o cn1rl o nnrrr nhrnrro nhipt
| | nat inrrr
int
et
nAccountNumber:
double dBalance:
25
256
/ constructeur BankAccount
public
BankAccount
()
nAccountNunber
dBalance
: 0.0;
= *tnNextAccountNumber
l
-^-L-^^
llElllu!cD.
duL!c
t/
,/
t/
l'{ai
//
DenonstrateDefaultConstructor
nontre
le
fonctionnenent
//
Hy0bject
il
et rrn
oh i
et i nterne
// ce membre est
une proprit de
ce membre
Mrr0thorhiant
public
a+a+i nflhi
LLlUVUJ
la
classe
}ly0ther0bject0;
est une proprit de 1'objet
ctnt.i
Mrrfltharh.inn+
LqLrL n rrJvLrrcrvuJtrLL
drrnnmi nh i
My0bject
new
/i
II
My0ther0bject
- cette
Mrrfltherflh jont
^1... r'rjvLrrrvuJLL
^"h1i ^ UId
PUUTIL
L
()
l
l
/l
Dmarrage de Main0
1.
2.
3.
57
258
4.
5.
con-structeur
I"h'Ot he rOb
J1
ec
6.
7.
Mission accorlplie
l.
2.
slectionnez Gnrer/Gnrer.
l.l
4.
D.
Slectionnez Dboguer/Dmarrer ou appuyez sur F5, et le programme s'excute jusqu'au point d'arrt dans MyOtherCb_jecr,
comme le montre la ligne en surbrillance dans la Figure 11.3.
6.
Figure 11.1:
La ligne en
surbrillance
-sur fond
rouge dans
le constructeur
I Fr rtl orll
r-
indique la
prsence
d'un point
d arrt.
w *. :. .';
Ii'r-] t,tr
Frqrrrrffle
._).
flassl.rs
.::,i
,:rrrL',rLet,i
tfi
ThfEad
:1, ).:,,
- r,"i.i.., a"
(i.1
,tr.
t,4
ag ., '..,
Au.g.&&
r,ehu,] -
- -
rS
1'1,:ln
,l
strir,l[] rrq:l
*1
:J
-:'
i.,
,$
+
Figure 11.2:
L'affichage
du
-dbogueur
de Visual
studio, juste
avant de
passer au
constructeur.
Exlortur d.
l'+om
I'rr :1,-rt'tttl:
!,11uf
Fpls
ttrr
Lar
:#
Pile de5
(:r
ntl
nAuromitiquel
L gnertirn a
x
J
AutEmtiqLe
rBssi
tr
ffipiluout
Ln 38
tr;,
ir
Col
f l ::,:t.t
a;
5g
260
ll!:l
r,t)t amr
tflassl.cs
t,frr: n5l:r
.,...,,
:;l;:;I 't
,t:t.
,:::r,
, '
,tr
:.
r'rt,r,l
,!a
Er
:i
:j
Figure 1 1,3 :
Le contrle
passe 0ans
I.TIrr--Llr_:
!riJ:1.r,: r:lti:
-le construc-
"'-
'.::r i ll.ir[
teur
I_=f
r.l r t:r|l
,.. f
,,
:i
l1'rr
.-!::]r':j[]
FluaLr.:1:{=
-il
l"h;t'}|horlhioe
avant de se
diriger vers
Autrntiqu
trleut
itnarjlrllaIal]rll :,rjlrr,:l:r l1
l!fi
l+i lfi:
T|pe
S;r
*}
:,r:frr [,r,:rr:|:.
le constructeur
l,Ii'Object.
Fr,3m d
Frie
Iaf r]rr!lrnl[ii]ll,
['etu,1
,rTr!ff!:Lrr
'
t,
:J
--J
:l
Figure 11.4 :
Le construc-
teur
M-,'Obi ec
reoit le
contrle une
fois que
l'o
jet
l,J,ln
statique
Itf.rlthonlh-i.e
+il
utontigue
TYpe
-
1f,,.
tr'rn
tu-ol
ttn,rr:Lr:l"t'rl.irfi,:rrlff,l:l,t,t
'elIif:f5]:tt|[,i:,t]:,_,:ir:l;!:]:r,l#
'rriir r.i-f i i l::f
[nr:riifitE[i:r]ii
':,r!lftl[i[]lll_:fst:rtr:r':1,:#
L4l ,rlhtrqui |
L gnerarln
F l d:: FF,l!
n t6
c0nstru it,
$rsl
reusii
)
l#
EJ
r.tl
Ln
{-,rl
,t
i-l',
---1
_,lr_-:
BankAccount
//
1000
et
augmentent
| |
int
nAccountNumber
= **nNextAccountNunber
chaque objet
ll
autres
memDres.
261
262
Uoqons comment se
des initialisations
fait la construction
auec
ic class Mv0hiect
// ce membre est
une proprit de
<tnt'i n Mvthorhiont
// ce membre
MvthprChiont
public
My0bj
la
classe
ctetirnhi
= new My0ther0bject0;
est une proprit de 1'objet
rlrrn-aminOhi = now Mrrthorh'iont
vvJ
ect
f)
L \ /
.
t
()
Surcharger le constructeur
On peut surcharger un constructeur, tout comme n'importe quelle autre
mthode.
Surcharger une fonction signifie dfinir deux fonctions portant le mme
nom, mais ayant des arguments diffrents. Pour en savoir plus, voyez le
Chapitre
7.
#"*$3
ffir]
I t"'7
f\
//
tl
BankAccountWithMultipleConstructors
ll
bancaire
using
System;
nmespac
e BankAccountWithMult
ip1 eConstructors
using Systen;
public class
C1ass1
public static
BanhAccount ba1
nerrr Bankccount
))
initiales
valides
= new BankAccount(100);
BankAccount ba3
Console.Read0;
return
0;
l
]
//
BankAccount
simule un
BankAccount
public class
t
augmentent
2 63
264
.'^..- re numro
//Il +4^^+:
r:.enr a Jour
de compte et 1e solde
1
i.nt
nAccountNunber;
double dBalance;
// fournit
public
BankAccount
()
nAccountNurnber
#nNextAccountNurnber
dBalance = 0.0;
public
BankAccount
(double dlnitialBalance)
dfaut
= #nNextAccountNumber ;
/l et nai"ntenant, le code propre ce constructeur
l/ commence avec 1e solde initial, condition qu'i1 soit positif
nAccountNumber
if (dlnitialBalance (
0)
dlnitialBalance =
l
dBalance
0;
: dlnitialBalance;
public
BankAccount
(int nlnitialAccountNumber,
double dlnitialBalance)
II
if
nlnitialAccountNumber = *tnNextAccountNumber
nAccountNumber
= nlnitialAccountNumber
dTnitialBalance
0;
dBalance = dlnitialBalance;
I
- 11!
public
string GetString0
t/
t/
t/
/ltoot =
o.oo
llnaz: ioo.oo
lltzlt = 2oo.oo
nnrrrroz crrr T'ntr6o nnrrr torminpr
Dans le monde rel, une classe effectuerait beaucoup plus de tests sur les
paramtres d'entre donns au constructeur, pour vrifier leur validit.
Ce sont les mmes rgles qui s'appliquent aux fonctions vous permettant de diffrencier les constructeurs. Le premier objet tre construit
par Main O, bai, est cr sans argument et est donc orient vers le
constructeur par dfaut pour y recevoir le numro de compte par dfaut
et un solde gal zro. Le deuxime compte, ba2, est envoy au constructeur BankAccount (double) pour y recevoir le numro de compte
suivant, mais il est cr avec un solde initial de 100. Le troisime, ba3,
reoit un traitement complet, BankAc c ount ( int , ri oub 1e ) , avec son
propre numro de compte et un solde initial.
)t
26 5
266
du monde rel que sur une page Web. La duplication cle rgles commerciales est la fois fastidieuse et source d'erreurs. Les vrifications peuvent
facilemer-rt se trouver en dsaccorcl. Par exemple, ch-r fait cl'une simple
erreur de codage, deux constructeurs peuvent appliquer atr solde cles
rgles diffrentes. De telles erreurs sont trs difficiles retrouver.
Vous prfreriez peut-tre qu'un constructeur en appelle urt autre. rnais les
constructeurs ne sont pas des fonctions : on ne peut pas les appeler.
Toutefois, vous pouvez crer une alternative sous la forrne cl'une fonction
qui effectue la vritable construction, et lui passer le contrle, comrne le
mOntre le programme Salrkr.cccJntCorrst r',-.i i ir: s:r,Fr,/':rr. , ';lt ci-dessous :
//
II
II
II
BankAccountContructorsAndFunction
bancaire
using Systen;
e BankAc c ount Cont ruct
name spac
r sAndFunct
ion
{
-^
uDrrr6
"^.;
Q"n+an.
ujLru,
publj-c class
C1ass1
initiales valides
Console.ItIriteline (bal.GetString 0 ) ;
BankAccount ba2
= new BankAccount
Console.Writeline
(ba2 . GetString
100)
0);
return
..")
0;
j
l
//
BankAccount
public class
- simule un simple
compte bancaire
BankAccount
double dBalance;
// place tout 1e vritable code
d'initiaiisation
Chapitre
public
{
Init(**nAceountNumber, 0'0)
public
(double dlnitialBalance)
BankAccount
tout
(int
nlnitialAecountNunber,
double dIni.tialBalance )
SankAccount
= nlnitialAccountNunber :
1e solde initial, condition qu'i1 soit positif
1r (0ln1t141alance \ u/
nAccountNunber
/l
I F
comnence avec
I
r-
^\
dlnitialBalance =
0:
dBalance = dlnitialBalance;
]
i
]
construction. Toutefois, cette approche n'est pas absolument irrprochable pour plusieurs raisons, dont I'appel d'une mthode d'un objet avant
que celui-ci ait t entirement construit n'est pas la moindre. C'est une
chose trs dangereuse.
Heureusement, ce n'est pas ncessaire. Un constructeur peut se rfrer
un autre avec une variante de I'utilisation du mot-cl tlris :
//
II
II
SankAccountContructorsAndThis
268
Q"a+an'
ublrrB
nare
oy b Ltrnl,
t
,,^;-^
urll
C,"^+^-,
Jy
Lcnr,
initiales
valides
= new BankAccount 0 ;
Console.l,iriteline (bal.GetString0 )
BankAccount ba2 = new BankAccount(100);
BankAccount ba1
..")i
l
1
double dBalance;
/l invoque 1e constructeur spcifique en fournissant
I I des valeurs par dfaut pour les arguments manqunts
nrrhlin
Ranlrnn9111
lerrrrr.uvur.!\/
0 : thiS(0, 0) tl
.
srr+v\v,
w/
I te vritable travail
public
BankAccount
(int
doub
nlnitialAccountNumber,
1e dlnitialBalance)
t
II
//
if
nlnitialAccountNumber = **nNextAccountNunber
l
nAccountNunber
= nlnitialAccountNumber
//
if
commence
avec
(dTnitialBalance
\v-.r+!rs,!**-nce
(\
0;
dTnitialBalance
0)
uJ
j
dBalance = dlnitialBalance;
]
J
bai =
new BankAccount
constructeur BankAccount
dfaut 0 et 0.0
(int,
public BankAccount0
: this(0, 0) tl
: this(0, d) {l
269
270
ue a(lare de
ses
objets
Par exemple, seule une mthode dfinie dans le mme espace de nom que
BankAccount peut crer un objet BankAccount avec Ie constructeur
dclar comme internal (pour en savoir plus sur les espaces de nom,
reportez-vous au Chapitre l6) :
ll
Ba*.kAccount
public class
BankAccount
double dBalance:
// invoque 1e constructeur spcifique en fournissant
I I des valeurs par dfaut pour 1es arguments manquants
internal
BankAccount
()
nAccountNumber
dBalance = 0:
= *tnNextAccountNumber
return String.Format
("11{Ol
{1 ;N1",
nAccountNunber, dBalance)
]
]
Ghapitre 12
L'hritage est une notion ordinaire. Je suis un tre humain, sauf I'instant o je
sors du sontmeil. J'hrite de certaimes proprits de la classe Humain, comme
ma capacit de dialoguer (plus ou ntoins), et ma dpendance l'gard de I'air,
de la nourriture et de boissclns contenant beaucoup de cafine. La classe
Hunain hrite sa clpenclance l'garcl de I'air, de I'eau et de Ia nourriture de la
classe llammif re, qui, elle-mnte, hrite de la classe Animal.
La capacit cle transmettre cles proprits un "hritier" est un aspect trs
puissant de la programmation oriente objet. E,lle permet de dcrire les
272
Les langages orients objet expriment cette relation d'hritage en permettant une classe d'hriter d'une autre. C'est cette caractristique qui
permet aux langages orients objet de produire des modles Plus Proches
du monde rel que les langages qui ne disposent pas du PrinciPe cle
I'hritage.
//
InheritanceExample
using
- offre 1a dmonstration
la plus simple de 1'hritage
System;
nanespace InheritanceExanPle
{
public class
BaseClass
Console.!'lriteline ("SoneMethod
")
l
l
BaseClass
public void
Some0therMethod0
l
l
public static
:");
//
=
;
2;
:");
sc. Sonre0therMethod ( )
Console.Read0;
return
0:
SoneMethod ( )
()
Sone0therMethod ( )
Appuyez sur Entre pour terminer. . .
Dans un langage orient objetcomme t#, nous disons que la classe Student hrite de la
classe Person. Nous disons aussi Que Person est une classe de base de Student, et que
Student est une sous-classe de Person. Enfin, nous disons qu'un Student EST-UNE
rerson.
? 273
274
Bemarquez que la proprit IST-UN n'est pas rflexive:un student EST_UNE person,
mais I'inverse n'est pas vrai. Une Person N'EST*PAS_UN Srudent. Un nonc comme
celui-ci se rfre toujours au cas gnral. ll pourrait se trouver qu'une person particulire
soit effectivement un Student, mais beaucoup de gens qui sont membres de la classe
Person ne sont pas membres de la classe Student. En outre,la classe Student possde
des proprits qu'elle ne partage pas avec la classe pe rs on. Par exemple, un studen r a une
moyenne de points d'UV, mais une person ordinaire n'en a pas.
L'hritage est une proprit transitive. Par exemple, si je dfinis une nouvelle classe
GraduateStudnt cOmme une sOus-classe de Student, alors un Graduatestudent St
aussi une Person. Et il doit en tre ainsi : siun GraduateStudent EST_UN student et un
Student EST-UNE Person, alors un GraduateStudent EST_UNE person. C0FD.
? 27 5
Cette capacit va de pair avec un troisime avantage de I'hritage. Imaginez que vous hritiez d'une classe existante. Un peu plus tard, vous vous
apercevez que celle-ci a un bogue qu'il vous faut corriger. Si vous avez
modifi la classe pour la rutiliser, vous devez rechercher manuellement
le bogue, le corriger et tester le rsultat, sparment, pour chaque application qui I'utilise. Si vous avez hrit de la classe sans lui faire de modifications, vous pourrez dans la plupart des cas introduire sans surprises la
classe corrige dans toutes les applications qui I'utilisent.
*\
e,
q/\
--"-ffi
ry
l/
ll
SinplesavingsAccount
d'un
using
inplnente un SavingsAccount
BankAccoTJnt
coiture
forne
System;
nanespace SimpleSavingsAccount
I
I
II
I
BankAccount
public elass
BankAccouni
t
II
//
public static
int
nNextAccountNunber
I
net jour 1e numro de cornpte et
pubLic int nAccountNunber;
public
deciural
-l
mBalance
et
augnentent
1000;
Ie solde pour
chaque objet
de compte
2 76
ob
jet
InitBankAccount (0)
nAccountNunber
**nNextAccountNumber
nBalance = mlni"tialBalancei
//
Balance (so1de)
public decimal
Balance
get I return
nBalance;
//
Deposit
- tout
public void
dpt
positif est
autoris
if
(mAmount
0)
nBalance *= mAnount;
l
]
1/ I'lithdraw
I
mWithdrawal)
if
(mBalance
(=
mWithdrawal)
nWithdrawal = nBalance;
]
nBalance -= rnl,lithdrawal ;
return
nrWithdrawal;
//
ToString
public string
]
]
//
SavingsAccount
compte bancaire
BankAccount
100)
InitSavingsAccount
(0,
mlnterestRate)
? 277
Ini-tBankAccount (mInitia1 )
this.mlnterestRate : mlnterestRate /
tO0:
// Accurnulatelnterest -
invoque une
fois par
priode
mBalance
//
ToStri-ng
- met le
compte sous
forne de chane
{11,')
",
ToBankAccountString0, mlnterestRate
100)
l
public class C1ass1
IL
ba.Deposit(100);
Console.1,{riteline("Conpte {0J", ba.ToBankAccountString0 ) ;
I I et naintenant un compte rmunr
SavingsAccount sa = new SavingsAccount();
sa. InitSavi.ngsAccount
(100,
sa.Accumulatelnterest
12. 5M)
Console.Read0;
return
0;
'|
J
1
)
1
278
ob
jer
La proprit Balance permet de lire le solde, mais sans donner la possibilit de le modifier. La mthode Deposit O accepte tout dpt positif. La
mthode Withd raw ( ) vous permet de retirer tout ce que vous voulez dans
la limite de ce que vous avez sur votre compte. ToBankAccountStrine o
cre une chalne qui donne la description du compte.
ld!75
f\!/
Y
- i'ai du mal
La relaton EST UN
La relation EST-UN entre -s3r.,i11gsr\ccount et BarrkAccount est mise en
vidence par la modification suivante c 1a s s 1 dans le programme
SirnpleSa-,'iiigsAccouni- de la section prcdente :
pub-Lrc
class Classl
/ fti rpetttennsi f -
ef f
ectue automaticuement
su Lvruo
1e rint 11 'rrn
ba,
chnrrp
LrtcYu
Chapitre
2:
rlpnim:i
ba. Deposit (mPay)
? 27I
mPnrr)
public static
t
I
et 1'affiche
DirectDeposit(ba, 100) ;
Console.liriteline("Compte
/
I et naintenanr un compre
{0J
",
ba.ToBankAccountString0 ) ;
rnunr
DirectDeposit(sa,
100) ;
sa, Accumulatelnterest ( )
i,lriteline ( "Conpte
Console,
Console.ReadO;
return
0;
]
]
Les effets de ce programme n'ont pas chang. La seule vritable diffrence est que tous les dpts sont maintenant effectus par la fonction
locale DirectDeposit | ), Les arguments de cette fonction sont le compte
bancaire et le montant dposer.
Remarquez (c'est le bon ct de la chose) que l'lain ( ) peut passer
DirecrDeposit O soit un compte ordinaire, soit un compte rmunr, car
ur.t SavingsAccc'unt EST_UN Bank,:corrni et en reoit par consquent
tous les droits et privilges.
membres de BankAccount
//
- compte bancaire
SavingsAccount_
SavingsAccount
public class
//
InitsavingsAccount
exprin
en
28
et
100)
bankAccount,
imal mlnterestRate)
this.bankAccount = bankAccount ;
this.mlnterestRate = mlnterestRate
100:
//
nrrbl
uv!ve
fois par
priode
\/
bankAccount.mBalance
= bankAccount.mBalance
(bankAccount.nBalance
* mlnterestRate) ;
mAmount)
i
I
/
I
Withdraw
rnWithdrawal)
I
t
return
bankAccount, Withdraw(mWi.thdra,,+a1 )
'l
.J
La relation
rii:'t
A_UN BanitAccounl--.
A UN
I
cr.e un nouveu compte rmunr
BankAccount ba = new BankAccount 0
I et y
dpose
sa.Deposit(100)
cent euros
;
0;
sa
chque
-]
ba.Deposit (nPay)
void SoneFunction0
t
suite.
La distinction entre les relations EST_UN et A_UN est plus qu'une question
de commodit logicielle, Cette relation a un corollaire dans le monde rel.
Par exemple, une Ford Explorer EST_UNE voiture (quand elle n'est pas
sur Ie toit). Une Explorer A_UN moteur. Si un ami me dit : "Viens avec ta
voiture", et que j'arrive dans une Explorer, il n'a aucun reproche me
faire (ou alors, s'il en a, ce n'est pas parce que I'Explorer n'est pas une
voiture). Il pourrait me faire des reproches si j'arrivais en portant dans
mes bras le moteur de mon Explorer.
La classe Explorer doit apporter une extension la classe Car, non
seulement pour donner Explorer accs aux mthodes de Car, mais
aussi pour exprimer la relation fondamentale entre les deux.
Malheureusement, un programmeur dbutant peut faire hriter Car de
Motor, donnant la classe Car accs aux membres de Motor, dont Car a
besoin pour fonctionner. Par exemple, Car peut hriter de la mthode
Motor. Go O, mais cet exemple met en lumire I'un des problmes qui
rsultent de cette approche. Mme si les tres humains s'expriment parfois
? 28 |
28
ob
jet
de faon ambigu, faire dmarrer une voiture n'est pas la mme chose que
faire dmarrer un moteur. L'opration dmarrage de la voiture dpend
videmment du dmarrage du moteur, mais ce sont deux choses distinctes : il faut aussi passer la premire, lcher les freins, et ainsi de suite.
PIus encore, sans doute, faire hriter Car de i{ctor est une reprsentation
errone des choses. Une voiture n'est tout simplement pas un type
particulier de moteur.
i("9K
il )
\g_/
Autres considrations
C# implmente un ensemble de caractristiques conues pour supporter
I'hritage.
Changer de classe
Un programme peut changer Ia classe d'un objet. En fait, c'est une chose
que vous avez dj vue dans cet exemple. SomeFunctlon O peut passer un
BankAccount ba;
SavingsAccount sa =
netll
SavingsAccout
ll
ox:
une conversion vers
ba
ba
: sa;
= (BankAccount)sa;
II
1o n^ct
avnl
ini+^
II tI r!
!qoL
yrfLrLc
sa
ba;
sa
// Nont
I I Ia conversion vers
I I ceci est correct
(SavingsAccount)ba;
1e
bas
te est
admise
cDL
^^* rrf r
1e haut
Savingsccounr.
? 2 83
l'excution
ProcessAmount(BankAccount bankAccount)
t
I I dpose une grosse somme sur
bankAccount.Deposit ( toooo. oo) ;
le
compte
^^.,-..1
^+^T-+^-^^+
Accumulatelnterest
^
(/ l)
]
yuurrL
^',L1.i^
a+a+.ia
LoLlL
"^.i,l
vulu
T^^+/r^^+/\
IcLUoL\l
28
Af\
e,
s/\
ob
jet
stre que I'objet qui lui est pass est bien un Sa,"'lngsAccounr avant
d'effectuer la conversion. C'est dans ce but que C# offre le mot-cl 1s.
L'oprateur i s admet un objet sa gauche et un type sa droite. Il retourne 'r f ue si le type I'excution de I'objet qui est sa gauche est
compatible avec le type qui est sa droite.
Vous pouvez modifier I'exemple prcdent pour viter I'erreur I'excu-
ProcessAmount(BankAccount bankAccount)
TestCast
D'un ct, je vous recommande fortement cle protger tous vos casts vers
le haut avec I'oprateur i s pour viter le risque d'une erreur I'excution,
d'un autre ct, je vous conseille d'viter tout cast vers le haut, si possible.
^qa/
ft?ll
\1l/
La classe ob
j ect
Les classes suivantes sont en relation les unes avec les autres:
public class
MyBaseClass {}
I'lyBase0lass {}
La relation entre ces deux classes permet au programmeur d'effectuer le test suivant
l'excution:
public class Test
{
GenericFunction(MyBase01ass
mc)
t
I I si 1'objet est vrainent
if (nc is !'lySubClass)
ll ...alors
1e
MySubClass msc
I
traite
une sous-classe..,
(MySubClass)mc;
suite
l
]
]
Dans ce cas, la fonction Gene r icFunc r i on O diffren cie les sous-classes de MyB a s eC l
en utilisant le mot-cl
as
is.
Commentfaire la diffrence entre ces classes, apparemmentsans lien entre elles, en utilisant
0prateur is ? C# tend toutes ces classes partir de leur classe de base commune,
object. Autrement dit, toute classe qui n'hrite pas spcifiquement d'une utre classe
hrite de Ia classe object. Ainsi, les deux dclarations suivantes sontidentiques:
le mme
oublic
class
'(
Test
la
? 28 5
286
o)
if
is l'IyClass1)
(o
MyClassl mcl
(MyClass1)o;
tttl
)
l
'I
Le mot-cl :-s
L'hritage et le constructeur
Le programme Inherir-anceExampl e que nous avons vu plus haut dans ce
chapitre repose sur ces horribles fonctions Inlt. . . pour initialiser les
objets BatrkAccoufit et SavingsAccoLiitt en leur donnant un tat valide.
quiper ces classes de constructeurs est certainement la meilleure
manire de procder, mais elle introduit une petite complication.
|
I
autonatiquenent
,,^.:-^
urlr
e.,-+^JJ
D LEIT,'
namespace
InheritingAConstructor
public class
t
C1ass1
public static
int Main(string[]
? 287
args)
Console.nead0;
return
public class
BaseClass
public
BaseClass
Base0lass
public Sub0lass0
.,
Console'I,lriteline ("Construc
l
font rien de plus qu'afficher
Les constructeurs de Baseclass et subclass ne
de I'obiet Baseclass
un message sur la ligne de commande. La cration
La cration d'un
invoque le construceur par dfaut de la classe BaseClass'
avant d'invoquer Son
objet SubClass invoque le constructeur de BaseClass
propre constructeur.
Ce programme donne la sortie suivante
tonstruction de
BaseCl'ass
Construction de SubClass
Appuyez sur Entre pour terniner"
'
288
dont elle ralise une extension. Il y a une raison cela : chaque classe est
responsable de ce qu'elle fait. Une sous-classe ne doit pas plus tre tenue
pour responsable de I'initialisation des membres de la classe de base
qu'une fonction extrieure quelconque. La classe BaseClass doit se voir
donner la possibilit de construire ses membres avant que les membres
de SubClass aient la possibilit d'y accder.
base
System
nanespace Exanple
{
SubClass
return
. . ")
0;
public class
BaseClass
public
BaseClass
publie BaseClass(int i)
t
COnSOle .l,/s
itoT.i
l
public class SubClass:
Base0lass
")
n11n | 1a
\11n1
Iteq
? 289
/\
Console.
l
oublic SubClass(int i)
{
Invocation de SubClassi)
Construction de BaseClass (default)
Construction de SubClass (default)
Invocation de SubClass(int)
Construction de BaseClass (default)
Construction de SubClass (int)
nnrrrraa
nyPUJ
!
orrr
U:
Frl
ro
!rtLrc
nnrrr
yvu!
torminor
Lsrrufrrs!
'..
procd
//
II
II
InvokeBaseConstruetor
using
nontre
System;
nanespace TnvokeBaseConstructo r
290
public
BaseClass
()
l
public BaseClass(int i)
{
Console.I^IriteLine("Construction de BaseClass(
[0])", i) ;
l
l
BaseClass
public
SubClass
()
public SubClass(int
il,
i2);
]
]
public class
C1ass1
public static
Console,lllriteLine("Invocation de
SubClass sc1 = new SubClass0;
SubClass 0
")
return
0;
l
]
l
Ce programme donne la sortie suivante
Invocation de SubClass 0
Invocation de SubClass(1,
2)
..")
? 2g
Construction de BaseClass ( 1 )
tonstruction de SubClass (1, 2)
Appuyez sur Entre pour terminer...
La classe BankAc
ount nodife
*u"uli3
,\tr
//
ll
ll
II
ConstructorsavingsAccount
implmente un SavingsAccount
forme d'un SankAccount : n'utilise
colnme
aucune mthode
virtuelle,
mai.s implmente
using
System;
namespace ConstructorSavingsAccount
/i
|
II
BankAccount
possdant
public cLass
BankAccount
tL
II
/l
//
tonstrueteurs
public
BankAccount
-(
(0
public
Bankccount
(decinal nlnitialBalance)
chaoue obiet
292
nAccountNumber = finNextAccountNunber
mBalance = mlnitialBalance ;
l
I
mme
chose
ici
//
savingsAccount
public class
intrts
//
I
tnitsavingsAccount
exprim en
pourcenrage (valeur comprise entre 0 et 100)
n'rl, 1.i^ avr_ngsAccount(decirnal
c-,,.;-^^^.
puur_r-c
nlnterestRate) : this(0, mlnterestRate)
I
: base(nInitial)
this.mlnterestRate = nlnterestRate
tOO;
l
I
mme
chose
ici
public class
C1ass1
n;-^^*n^-^^..ir
//// u].recrueposlr
- effectue automatiquement le dpt d'un chque
public static void DirectDeposit(BankAccount ba,
decimai npay)
{
DirectDeposit(ba,
100)
return
l
0;
Ghapitre 12
: Acceptez-vous
'hr itage
? 293
constructeur par dfaut qui ne I'aclmet pas. Afin cl'viter toute publication de
code dans le constructeur, le constructeur par dfaut invoque le constructeur
de tsanL<A.rcc'it.'ri:,, . ,:,i- 1 .ti:t:ri- - I elt utilisant le mot-cl thls.
La classe Sa-"'ir,gsrLrLrr,rrl: fournit galenrent deux constructeurs. Le
constructeur S a.lt:,gs,!c..,,:nt i'i:rt-er:sr- f a+,e) invoque le constructeur
SavingsAccoi.Lil i i tresi t ir-:. iit.lttai baiance; en lui passant un
solde initial de 0. Ce constructeur, le plus gnral, passe le solde initial au
constructeur Banli;(rij.iLLnt rir,tial baiance) en utilisant le mot-cl
base, comme le montre de faon graphique la Figure 72.1.
Figure 12.1 .
Le cheminement de la
constru ction
BankAccount(0)
d'un objet
(.errino<Arnn mt
en utilisant le
c0nstructe u r
par dfaut.
gl
donne au solde
la valeur par
dfaut 0
- 200,00
- 112,50
(12,5ti)
Le destructeur
C# offre aussi une mthode qui fait I'inverse du constructeur, appele le
destructeur. Le destructeur porte le nom de la classe, prcd par un tilde
(-). Par exemple, la rnthode -Faseijlass est le destructellr de BaseCiass.
C# invoque le destructeur lorsqu'il n'utilise plus I'objet. Le destructeur
par dfaut est le seul qui peut tre cr, car le destructeur ne peut tre
invoqu directement. En outre, le destructeur est toujours virtuel.
294
Le ramasse-miettes et le destructeur G#
mthode du destructeur estbeaucoup moins utile en C#que dans d'autres langagesorients
objet, comme C++, car C# possde de ce I'on appelle une destruction non dterministe.
La
En
Le destructeur de C# est non dterministe parce qu'il ne peut pas tre invoqu avant que
I'objet it t rcupr par le ramasse-miettes, ce qui peut se produire longtemps aprs qu'il
a cess d'tre utilis. En fait, si le programme se termine avant que l'objet soittrouv par le
ramasse-miettes et retourn au tas, le destructeur n'est pas invoqu du tout.
Au bout du compte, l'effet qui en rsulte est qu'un programm eur C# ne peut pas se reposer
sur le destructeur pour oprer automatiquement comme dans un langage comme C++.
Chapitre 13
polymorphisme
Dans ce chapitre :
L'embarras du choix : masquer ou craser une mthode de la classe de base.
Construire des classes abstraites : parlez-vous srieusement ?
Dclarer comme abstraites une mthode et la classe qui la contient.
Faire commencer une nouvelle hirarchie au-dessus d'une hirarchie existante.
Empcher qu'une classe puisse tre transforme en sous-classe.
jlff
tl$/,
Y
Si
Un four micro-oncles est un type de four, non pas parce qu'il a I'air d'un
four, mais parce qu'il remplit les mmes fonctions qu'un four. Un four
micro-ondes remplit aussi des fonctions supplmentaires, mais au moins, il
remplit les fonctions de base d'un four - et le plus important, c'est qu'il fait
chauffer mes nachos quand je dis "StartCooking". Le processus interne
que doit mettre en uvre le four pour remplir sa mission ne m'intresse
pas, pas plus que le type de four dont il s'agit, ni son fabricant.
296
De notre point de vue d'tre humain, la diffrence entre un four microondes et un four conventionnel ne semble pas de la plus haute importance,
mais envisagez un instant la question du point de vue du four. Les tapes
du processus interne mis en uvre par un four conventionnel sont compltement diffrentes de celles d'un four micro-ondes (sans parler d'un four
convection).
Le pouvoir du principe de I'hritage repose sur le fait qu'une sous-classe
n'est pas oblige d'hriter I'identique de toutes les mthodes de la classe de
Ce n'est
-u#t$ Donner le mme nom deux fonctions (ou plus) s'appelle surchorger un
\
=i -^- ) no- de fonction.
PY
Les arguments d'une fonction font partie de son nom complet, comme le
montre I'exemple suivant :
oublic class
l4vClass
nrrhlin
I f.aire
quelque chose
nrrhl in cfrtin
rrnirl rrnntinn/int\
srr
urv.r
\Jrrr/
d)
chose d'autre
l
public static void Main(stringll args)
t
AFunetion0;
Alunction(l);
AFunction(2.0);
#5
e,
MyClass
public
UrClass
publi.c static
{
vo
/\
urutass.AtunctlonU ;
// invoque la fonction nenbre MyClass.
My0lass ncObject : new MyClass0;
ncObject.Al'lethod0;
AMethod ( )
) (avec
la vtre, a marche).
? 29 7
29 8
ob
jer
BankAccount
(int
nAccountType)
BankAccount
(decimal mInitialBalance,
bool isSavingsAccount)
{
mBalance
= mlnitialBalance
nAmount)
i
ll
.,
mBalance
-:1,50M:
mAmountToWithdrar,v
mBalance
mBalance
return
-=
nAmountToWithdraw;
mAnountTo}.fithd
rar^r
'I
class Mytlass
{
public void
SomeFunction0
t
I
I le veux ne crer
BankAccount ba
un conpte rrnunr
.e"*li3
h
ffirii
I tY,x
t,
using Systen;
nnespace Hidi.ngl,lithdrawal
t
public
BankAccount
(decimal mlnitialBalance)
mBalance = mnitialBalance
public decimal
Balance
nrrhl
mAmount)
t
mAmountToWithdraw = nAmount;
(nAurountoWj.thdrai,s
mBalance)
decinal
if
mAmountoWithdrarar
= mBalance
l
mBalance
return
-= nAnountTol,lithdraw;
mAnountTol,Ii.thdraw
2gg
300
//
SavingsAccount
compte bancaire
BankAccount
//
SavingsAccount
- 1it
SavingsAccount (decimal
public
dec
base
et 10)
mInitialBalance,
irnal mlnterestRate)
(mInitialBalance)
this.mlnterestRate = mlnterestRate /
100;
// Accumulatelnterest -
invoque une
rI
mBalance
mBalance
!v
i
\
fois par
priode
)
/
(mBalance
mTnterestRate);
//
Withdraw
// soustrait 1.50
base. 'vlj-thdraw(
| | VVU UVUVgL
I I "^"^
return
l . 5t't) ;
maintenant
lnaLLLLgllIlL
EtlELLUtrl
effectuer
un
Ull
retrait
!CL!1L
nrri
restp
avec ce
re
!sLC
yur
dVLu
l
]
nlrhri^
PUUTfL
^t^^a
Urdb
t r^^^1
ufdD
MakeAWithdrar+al(BankAccount ba,
decimal nAmount)
{
BankAccount ba;
avrngsAcCounL sa;
ll cre un compte bancaire, en
C^"-i-^^aanln+
retire
100
F, et
00M)
// essaie de faj-re la
mme
? 30 I
ba.Balance);
Console.l,iriteLine
Console.Read{);
return
0;
Dans ce cas, la fonction l'1ain () cre un objet BankAcco'rnt avec un solde initial
cle 200 F, et effectue un retrait de 100 F. l"laln 0 rpte cette opration avec un
objet Sa.,'ingsAc.ourr:. Lorsque l'lain 0 effectue le retrait depuis la classe de
base, llaril,Ac c cunt . irii thd r ar" ( ) effectue cette tche avec un aplomb remarquable. Lorsque l"iain O retire ensuite 100 F du compte rmunr, la mthode
Savings,-.,1,' ;rLrrt
t(9,
y
mesure du possible. faites en sorte que ce soit la classe de base qui manipule
302
la
classe de base ?
le
membre
trtlj.thdrarv
(decimal)', car i1
hrit
dec
imal
)'
C# essaie de vous dire que vous avez crit dans une sous-classe une
mthode portant le mme nom qu'une mthode de la classe de base. Estce vraiment ce que vous vouliez faire ?
iNmoinsdepasser|afentreSortiepourvoircequiyestaffich'Dans
t\7,
Y
presque tous les cas, vous y verrez un avertissement qui vous prvient que
quelque chose pourrait bien vous mordre si vous n'y mettez pas bon ordre.
Le descripteur ne" indique C# qu'une mthode est redfinie intentionnellement et que ce n'est pas le rsultat d'une ngligence :
//
new
{
Cette utilisation du mot-cl new n'a rien voir avec I'utilisation du mme
mot-cl pour crer un objet.
permettrai de faire remarquer ici que c'est I'une des choses que je
1r${Qa" Je me
\ trouve agaantes chez C# (et C++ vnt lui) : faites ce que vous voulez
^r,7rt7
avec mes mthodes, mais ne surchargez pas mes mots-cls. Quand je dis
\/ ) new, c'est que je veux crer un objet. Ils auraient pu utiliser un autre motcl pour indiquer une surcharge intentionnelle.
:(dw
ReUenr
? 303
la ba s e
if
(++nNunber0fl^lithdrawalsThisPeriod
1)
dArnountl,lithdravn
t=
l,lithdraw (1 . 5 ) ;
return
dAnountl{ithdrar+n
tn]; I I je m'appelle
moi-nne
l
L'appel fn O depuis fn 0 aboutit s'appeler soi-mme, sans fin. De mme,
un appel de Withdraw 0 elle,mme fait qu'elle s'appelle elle-mme en boucle,
comme un chat qui court aprs sa queue, jusqu' ce que Ie programme finisse
par se planter.
D'une manire ou d'une autre, il vous faut indiquer C# que I'appel depuis
SavingsAccount . Withdraw ( ) est l pour invoquer la mthode de la classe
de base, BankAccount . \,/ithdraw 0 . Une solution consiste faire un cast du
pointeur this dans un objet de la classe BankAccounr avant d'effectuer
I'appel.
//
tlithdraw
ll
new
{
I
dans un
objet de la classe
BankAccount
30 4
= (BankAccount)this;
invoque Withdrar.+0 en utilisant cet objet BankAccount
appelle 1a fonction BankAceount.Withdraw0
double dAmountl^lithdrawn = ba.Withdraru(dWithdrawal) I
if (**nSurrber0fWithdrawalsThisPeriod ) 1)
BankAccount ba
//
i/
{
f=
dAnountWi.thdralrn
ba , I^Iithdrar,r (1
.5
return
dAtnountWithd
rar,un :
=t
.-!/
Le mot-cl base de C# est la mme chose que this, mais redfinit le cast
la classe de base, quelle que soit cette classe :
ll
II
With&aw
new
t
II
/ sousrrait 1 .50 F
base. l,lithdraw(
.5M)
base.Withdrai,r(mWithdrawal)
avec ce
qui reste
L'appel base.,,iit-hdra-,
(;
? 30 5
Le polqnorphisme
Vous pouvez surcharger une mthocle d'une classe de base avec une mthode d'une sous-classe. Aussi simple qu'elle paraisse, cette solution apporte
des possibilits considrables, et de ces possibilits viennent des dangers.
nrrhl i r. ctnti
void
decinal
rnAmount)
BankAccount ba;
SavingsAccount sa;
ba = new BankAccount(200M);
(ba,
MakeAWithdrawal
100M)
(sa, 100M) ;
//tl affiche 1e solde rsultant
MakeAWithdrawal
return
]
Read
0;
306
voqu pr un interndiaire,
Le solde de BankAccount est i00,00 F
Le solde de SavingsAccount est 100,00
Appuyez sur Entre pour terminer...
.'r^i
Dans certains cas, vous ne vouclrez pas utiliser le type dclar. Ce que vous
voudrez vrailnent, c'est effectr-rer I'appel sur la base du type rel, c'est--dire
le type i'exctrtion, par oppositiort au type dclar. Cette possibilit de
dcider I'excution s'appelle polyrnorphisme, ou late binding (liaison
{:/rr
=qE)
? 307
de
se
se
le
polymorphisme.
Le polymorphisme est un aspect crucial de la puissance de la programmation oriente objet. Il est si important qu'un langage qui ne le comporte
pas ne peut pas tre prsent comme un langage orient objet.
1t$!Qa.
\ Un langage qui comporte des classes mais pas le polymorphisme est
^.v7q
appel langage base objets. Le langage Ada en est un exemple.
'(dE,)
donner encore un exemple pour vous le montrer. Imaginez que j'aie crit
ce programme succs mondial qui utilisait une classe nomm Student.
Aprs quelques mois de conception, de codage et de test, je publie cette
application pour rcolter les avis de mes collgues et des critiques en
tout genre (on a mme parl de crer une nouvelle catgorie de prix
Nobel pour le logiciel, mais par modestie jai ignor ces suggestions).
Le temps passe, et mon patron me demande d'ajouter ce programme la
prise en compte des tudiants diplms, qui ne sont pas tout fait identi-
ques aux tudiants ordinaires (ils revendiquent sans doute de ne pas tre
identiques du tout). Supposez que la formule de calcul des frais de scolarit
soit compltement diffrente de celle utilise pour un tudiant ordinaire.
Mais mon patron ne sait pas et ne veut pas savoir qu' ce niveau de profondeur du programme il y a de nombreux appels la fonction calcTuition O .
void SomeFunction(Student
s)
s.CalcTuition0;
continue
308
Tout cela ne se prsente pas mal, sauf pour trois choses. Pour commencer, ce n'est I qu'une fonction. Supposez que calcTuition () soit appele
depuis de nombreux endroits. Supposez aussi que calcTuition i) ne soit
pas la seule diffrence entre les deux classes. Mes chances de trouver
tous les endroits qui doivent tre modifis ne sont pas des plus leves.
Avec le polymorphisme, je peux laisser C# dcider de la mthode appeler.
MakeAWithdrawal(BankAccount ba,
decinal
mArnount)
if ba is
Savi-nesAccount
SavingsAccount sa
sa . Withdraw (urAmount )
(SavingsAccount)ba;
;
el se
ba . Withdraw(mAmount )
=[J\y
\/
En fait, I'approche
? 309
mauvaise
ide. Elle ncessite que SomeFunction O connaisse tous les diffrents
types d'tudiants et quels sont ceux qui sont reprsents par les diffrentes classes. Cela fait peser une trop lourde responsabilit sur les paules
de la pauvre vieille SomeFunction O . Pour le moment, mon application ne
connat que deux types de comptes bancaires, mais supposez que mon
patron me demande d'en implmenter un nouveau, CheckingAccount, t
que celui-ci soit associ une autre politique de Withd raw ( ) . Mon programme ne fonctionnera pas correctement si je ne trouve pas toutes les
fonctions qui testent I'excution le type de cet argument.
,,"$$Ig
,,.&v- l- lrJ,r
,\
l-..ffvn
I I"\7
ry
//
II
folynorphiclnheritance
redfinir
using
/i
e Polymorphic Inheritanc
BankAccount
public class
i
I
polynorphi.sne pour
une mthode dans la classe de base
System;
nmespc
* utilise le
L ,
BankAccount
la
mne chose
ici
decinal
if
I
nAmountToWithdrarrr
(nAmountToWithdraw
rnAnount
mBalance)
mAnount)
3 |0
mAmountTol^lithdraw
mBalance
l
nBalance -= mnountToWithdraw;
return
mAmountToWithdraw
//
SavingsAccount
compte bancaire
BankAccount
l ,
la mme chose ici- aussi
/ tllthdraw * tout retrait est autoris jusqu' la valeur
II
du solde ; retourne le nontant retir
l
// soustrait 1.50 F
base.l{ithdrav(1,5M);
I
return
base. Withdrarq(rirWithdraval)
retrait
public class
C1ass1
MakeAWithdrawal(BankAccount ba,
decimal
mArnount)
I
t
ba. Withdraw(mAmount)
,ll
..
nae de
rla changement
nlrcnnnmnn+
pas
i^-i
ici
-^-1,,^
plus
non
l
l
l
-r,r'i
thd ra',\i i. ) est marque comme .,,i rrual dans la classe de base
BarrkAc.culrt. alors que la mthode i,,ithdraw O de la sous{lasse est marque
avec le mot<l L).u,errlCe. Bien que la mthode MakeAl,/ithdrawal 0 soit
inchange, le programme donne une sortie cliffrente parce que I'appel
ba.l^rithri ra-w ( ; est rsolu sur la base du type de ba I'excution.
La fonction
^$C .z
7X
t(?,
Y
? 3l I
Pour vous faire une ide prcise de la manire dont tout cela fonctionne, il
est ncessaire que vous excutiez le programme clans le dbogueur de Visual
Studio. Gnrez le programme comme d'habitude, et appuyez sur la touche
Fl1 autant de fois que ncessaire pour faire avancer le programme pas pas.
Il est impressionnant de voir le mme appel aboutir une mthode ou une
autre selon le moment o il se produit.
La ytriode abstraite de C#
ce que je sais, un canarcl est un type cl'oiseau, de mme qu'un colibri et
une hirondelle. En fait, tout oiseau est un sous-type d'oiseau. La rciproque de ce principe est qu'il n'existe pas d'oiseau qui ne soit pas un soustype d'oiseau. Cette remarque ne paralt pas trs profonde, mais en fait,
elle I'est. L'quivalent logiciel de cet nonc est que tout objet oiseau est
une instance d'une certaine sous-classe de Ci seau. Il n'y a pas d'instance
de la classe Oisea'i.
3 |2
Figure 13.1
Une description sous la
forme UML
des classes
Hi ghS choo i
:
et Unive r
University
- numStudents
- numStudents
+ nAvgSAT
Student
+ Enroll 0
+ Enroll 0
+ GetGrant 0
sily.
Le langage UML
Le langage
dfinir clairement une grande partie des relations entre des objets dans un pr0gramme. L'un
des avantages d'UML est que I'on peut en ignorer les aspects les plus spcialiss sans en
perdre entirement la signification.
Les caractristiques de base d'UML sont les suivantes
tl
Une classe est reprsente par un rectangf e, divis verticalement en trois sections.
Le nom de la classe apparat dans la premire section en partant du haut.
tl
tl
Les membres prcds par un signe + sont publics, et ceux qui sont prcds par un
signe - sont privs. UML ne dispose pas de symboles pour reprsenter la visibilit et
la protection.
tl
? 313
Une flche entre deux classes reprsente une relation entre ces deux classes. Un
nombre au-dessus du trait exprime la cardinalit. Le symbole "*" signifie un nombre
quelconque. Si aucun nombre n'est prsent, la cardinalit estsuppose gale 1.
Ainsi, dans la Figure 13.1, vous pouvez voir qu'une universit peut avoir un nombre
quelconque d'tudiants.
tl
Un trait se terminant par une grande flche largement ouverte exprime la relation
EST-UN {l'hritage). D'autres types de relations sont galement reprsents, dont la
relation A-UN.
3 I tl
High School
Figure 13.2
L'hritage de
HighSchcol
-simplifie la
c
+ Enroll 0
lasse
Univer
sity,
mais
introduit
quelq ues
problmes.
- numStudents
il
University
+ nAvgSAT
+ GetGrant 0
? 3l 5
et expdi au public qui n'attend que lui (bien str, je n'ai pas oubli d'y mettre
le nombre de bogues ncessaires pour que tout le monde veuille s'offrir,
moyennant un prix tout fait raisonnable, la mise jour vers la version 2).
Quelques mois passent, et l'tablissement dcide de modifier sa procdure de recrutement. Il ne sera pas vident pour tout le monde qu'en
modifiant la procdure de recrutement de la high school c'est aussi la
procdure d'inscription au collge voisin qui a t modifie.
Comment faire pour viter un tel problme ? Une solution est de ne pas aller
l'cole, mais une autre consiste corriger la source du problme : une universit n'est pas un type particulier de high school. Il existe bien une relation entre
les deux, mais cette relation n'est pas EST_UN. Au contraire, universits et high
schools sont deux types diffrents d'tablissement scolaire.
La Figure 13.3 dcrit cette relation. La classe School nouvellement dfinie
contient les proprits communes des deux types d'tablissement, y
compris leurs relations avec les objets Student. School contient mme la
School
{abstract}
numStudents
+ Enroll 0
Figure 13.3
Hl ghS cho
9t
s
Univer
ity
- {abstract}
o1
-
doivent
I'une et
I'autre tre
bases sur
une classe
c0mmune
School.
+ nAvgSAT
+ Enroll 0
+ NameFavorite
+ Enroll 0
+ GetGrant 0
3 |6
#\
(l.,/
Etablissement scolaire
r--
Figure 13.4:
Le factoring
prod u it
g n ra lement des
c0uc nes
L{"+,q
;r
Lqi:e
supplmen-
taires dans
la hirarchie
d'hritage.
Suprieur
Ecole suprieure
l
Universit
Classes prparatoires
Vous
Sch,:o
? 3l 7
Figure 13.5:
ll nyapas
de factoring
"universel".
La manire
ppropri e
de dfinir les
a
flasses
dpend en
partie du
problme
i
l
I
rsoudre.
Collge
Classes prparatoires
ll ne me reste Qu'un
concept
:la
classe abstraite
d'un compte rniunr sont diffrentes de celles d'un compte chque. Vous
aurez donc implmenter SavingsAccoulrt . i'jithd rawal ( ) diffremment
de ClireckingAccount .ldirhdraw O. Mais comment implmenter
Patk..cc:)'-:.--
.'.
i ,hr t ,^,a I
3l 8
"Quelles sont les rgles pour effectuer un retrait sur un compte ?" demandez-vous, plein d'espoir.
"Quel type de compte ? Un cornpte chque ou un compte rmunr ?"
"Un compte, rpondez-vous, simplement un compte."
Regard vague et dsespr.
Le problme est que cette question n'a pas de sens. Il n'y a pas de compte qui
soit "simplement un compte". Tous les comptes (dans cet exemple) sont soit
des comptes chque, soit des comptes rmunrs. La notion de compte est
une notion abstraite qui rassemble les proprits communes aux deux classes
correspondant une ralit concrte. Elle est incomplte, car il lui manque la
proprit critique',,\rithciraw O (en allant plus loin dans les dtails, vous
trouverez peuttre d'autres proprits qui font dfaut un simple compte).
Le concept de EarLkAccount est un concept abstrait.
..^.:
-^
uJrr
ll
II
C,,a+^*.
yLtrilI
'
AbstractBase0lass
3 I8
"Quelles sont les rgles pour effectuer un retrait sur un compte ?" demandez-vous, plein d'espoir.
"Quel type de compte ? Un compte chque ou un compte rmunr
?"
une notion abstraite qui rassemble les proprits communes aux deux classes
corresponclant une ralit concrte. Elle est incomplte, car il lui manque la
proprit critique l^Jithdraw 0 (en allant plus loin dans les dtails, vous
trouverez peuttre d'autres proprits qui font dfaut un sirnple compte).
Le concept de BankAccount est un concept abstrait.
.)
usi-ng Systen;
ll AbstractBaseClass
I
3l 6
*\
=(0,
c'est le cas. Par exemple, un programme crit pour une hirarchie plus
complte d'tablissements scolaires pourrait avoir une structure de
classes plus proche de celle montre par la Figure 13.4.
Etablissement scolaire
Figure 13.4:
factoring
produit
Le
Suprieur
supplmen-
taires dans
la hirarchie
d hritage.
'---3__,
1ry.":_l
E."b;pd;l
Universit
Classes prparatoires
Vous pouvez voir clue j' ai insr une nouvelle classe entre University et
' l r's. J'ai subdivis cette nouvelle classe en Coileee et
Sch"..r:!i;.--r.
3 |4
High School
Figure 13.2
L'hritage de
HlghSchool
-simplifie la
- numStudents
+ Enroll 0
classe
Univer
sity,
mais
il
introd uit
quelq
es
problmes.
+ GetGrant 0
3 |2
Figure 13.1 :
Une description sous la
forme UML
des classes
Hi ghS chc o i
University
- numStudents
etUrrlver
+ Enroll 0
+ GetGrant
Student
+ nAvgSAT
ci trr
re9!Qa.
zo^w7-7
Le langage UML
Le langage UML {Unified Modeling Language} est un langage de modlisation, permettant de
dfinir clairement une grande partie des relations entre des objets dans un programme. L'un
des avantages d'UML est que I'on peut en ignorer les aspects les plus spcialiss sans en
perdre entirement la signific ation.
,/
/
/
Une classe est reprsente par un rectangle, divis vefticalement en trois sections.
Le nom de la classe apparat dans f a premire section en partant du haut.
Les membres donne de la classe apparaissent dans la section du milieu, et les
mthodes dans la section du bas. Si la classe n'a pas de membres donne ou de
mthodes, vous pouvez omefire la section du milieu ou celle du bas.
Les membres prcds par un signe + sont publics, et ceux qui sont prcds par un
signe - sont privs. UML ne dispose pas de symboles pour reprsenter la visibilit et
la protection.
3l 0
mAmountToWithdraw
= nBalance ;
l
nBalance -= mAnountToWithdraur;
return
mAmountToWithdraw
//
SavingsAccount
compte bancaire
BankAccount
1a mrne chose ici aussiWithdra$ - tout retrait est autoris jusqu' 1a valeur
du solde ; retourne 1e nontant retir
override public decimal Withdraw(decimal mWithdrarual)
I
//
II
I
/1 soustrait 1.50 F
tl
base.Withdrari( 1 . 5M) ;
// vous pouvez maintenant effectuer un
return
base.Withdrarr(mWithdra,,ral)
retrait
avec ce
qui reste
void
vvlu
LLIl
^ .+"+is
(BankAccount
ba,
MakeAllithdrawal
lls^cnnfLlrurqwcf
\!qrrnrr
dec
imal
rrrAmount
ba . Withdraw (nAmount )
non Plus
]
l
l
1
voqu
La fonction \^rithdraw
308
Tout cela ne se prsente pas mal, sauf pour trois choses. Pour commencer, ce n'est I qu'une fonction. Supposez que calcTuition () soit appele
depuis de nombreux endroits. Supposez aussi que calcTrrition O ne soit
pas la seule diffrence entre les deux classes. Mes chances de trouver
tous les endroits qui doivent tre modifis ne sont pas des plus leves.
Avec le polymorphisme, je peux laisser C# dcider de la mthode appeler.
C1ass1
jn cratis void
MakeAWithdrawal(BankAccount ba,
deci.mal nAmount
if
ba
is
SavinssAccount
SavingsAccount sa
(SavingsAccount)ba;
sa . Withdraw (mAmount )
e1 se
ba
Withdrav
(mAmount
MakeA'uJi
1t$!Qa.
7^H\
V /
\/
= \
Chapitre 14 : Ouand une classe n'est pas une classe : l'interface et la structure
EST-UN
Int32
portion clu
nombres
entiers
I-e programme termine son numro de cirque en utilisant une fois de plu.s
la descendance d'cb j ect. Toutes les sous-classes d''',r: j i,r i ({:'e.st-e\-clire
toutes les classes) implmentent toS:r-rrgi,. Par c<insc1uent, si nous
Affichase
de tous 1es obiets de la Liste
- --"*bpst (th'i c is a <trino)
0hiets|.0'l
L-r
--J--"-
rlhr^+ll,r
wuJLDLTJ
Appuyez
^^+
CL
1(
\J.J
(trrrr^trrroFvemnle)
rl,r nr^^..-*o
p!u!dill[E
uu
\)
'qE,
57
306
or.r
par un interr:idiaire,
Le solde de BankAccount est 100,00 F
Le solde de SavingsAccount est 100,00
voqu
Qu'U
tqpe dclar
.)
Dans certains cas, vous ne voudrez pas utiliser le type dclar. Ce que vous
voudrez vraiment. c'est effectuer I'appel sur la base du type re[, c'esl--dire
le type I'excr,rtion, par opposition au type dclar. Cette possibilit de
dcider I'excution s'appelle polymorphisme, ou late binding (liaison
tardive). Utiliser le type dclar s'appelle early binding (liaison prcoce).
Chapitre 14 : Ouand une classe n'est pas une classe : l'interface et la structure
nrlh, i rtoD
PUUTIL
'^^-1
uJdb
.r'
OutputFunction(2);
I I en fait, i'ous pouvez utiliser directenent 1e mme objet
Console,T,,/riteLine("Extrait directement = {0}", 3.TcStringO)
I I cect peut tre trs utile ; vous pouvez extraire un int
I
I d'tne liste
ltl = z;
if (objectsIindex] is int)
{
int n = (int)objectsIindex];
Console.|lriteLine("L'1ment numro {01 est [1]",
index, n);
)
des types
int
nCount = 0;
(nhiont
fnroanh
!VIgOLI!\VUJLL
ir VVJULD/
ahiantol
V
^ IIT
Console.l^lriteLine("0b3'ets
nCount**, o.ToString0 ) ;
]
I
35 5
30 4
= (BankAccount)this;
// invoque inlithdraw0 en utilisant cet objet
I I appelle 1a fonction BankAccount.Withdrav0
BankAccount ba
BankAccount
if
(+*nNuniberOfi,lithdrawalsThisPeriod
*= ba.Withdraw(1.
5)
1)
dAmountWithdrarrn
return
dAmountl{ithdrawn
/l
II
Withdraw
new
mhrithdrawal)
base. Withdrai,r(ml,Iithdrawal )
avec ce
qui reste
( .r
id = (100.0,
200.00)
1t$!Qa" Cette unification des types de variables est trangre aux autres langages
!,/t-t
'qE,
353
302
.)
)' , car il
C# essaie de vous dire que vous avez crit dans une sous-classe une
mthode portant le mme nom qu'une mthode de la classe de base. Estce vraiment ce que vous vouliez faire ?
message n'est qu'un avertissement. Vous ne le remarquerez mme pas,
^$st -a Ce
moins de passer la fentre Sortie pour voir ce qui y est affich. Dans
7X
presque tous les cas, vous y verrez un avertissement qui vous prvient que
t\!|,
quelque
Y
pourrait
pas
chose
bon ordre.
Le descripteur new indique C# qu'une mthode est redfinie intentionnellement et que ce n'est pas le rsultat d'une ngligence :
/i
new
(
t
I
U
1e$\a.
^v7|
Cette utilisation du mot-cl new n'a rien voir avec I'utilisation du mme
\ trouve
'qE,
avec mes mthodes, mais ne surchargez pas mes mots-cls. Quand je dis
new, c'st que je veux crer un objet. Ils auraient pu utiliser un autre motcl pour indiquer une surcharge intentionnelle.
Chapitre 14 : Ouand une classe n'est pas une classe: l'interface et la structure
dNewValue)
n : nNevValue;
d : dNewValue;
//
tt
^.
ToString
^r^^
ufdbU
/ r^-^1
\rId5
i-nitiale de test")
"
OutputFunction (test ) ;
// essaie de modifier
^^^^^ argument
Iilt conme
ChangeReferenceFunction
Console.}lriteLine("Va1eur de
'
OutputFunction (test ) ;
int
{
t.N =
newValue;
Test.D = dNewValue;
l
35 |
300
//
SavingsAccount
compte bancaire
BankAccount
/
I
SavingsAccount
- iit
SavingsAccount (decimal
public
et
100)
mnitialBalance,
decimal mlnterestRate)
base
(nInitialBalance)
this.mlnterestRate = mlnterestRate
100;
//
Accumultelnterest
invoque une
fois par
priode
(niBalance
mTnterestRate);
/i
II
Withdraw
mWithdrar+al)
/l soustrait 1.50 F
base.l,lithdrav ( i . st't) ;
I I vous pouvez maintenant effectuer un
return base, Withdraw(ml,Iithdrawal) ;
retrait
l
r I |
1 , - ,
- , -1
^1
public
Classl
class
nrrhf
ic gtar-ie voiC
MakeAWithdrawal(BankAccount ba,
decimal nAmount)
a
public static
int Main(stringIl
args)
BankAccount ba;
SavingsAccount sa;
I I ere un conpte bancaire, en
//
retire
100
F, et
ba = new BankAccount(200M);
ba . Withdraw { I 00M)
//
essaie de
faire
sa =
nel,,r
Chapitre 14 : Ouand une classe n'est pas une classe: l'interface et ta structure
public struct
Test
private int n;
public Test(int
n)
this.n = n:
l
]
ffi
349
298
BankAccount
(int
nAccountType)
BankAccount
(decimal nlnitialBalance,
bool
{
mBalance
isSavingsAccount
mlnitialBalance;
this.isSavingsAccount
isSavingsAccount;
l si
'i
;t
t
nBalance -= 1.50M;
mBalance
mBalance
return
-:
nAmountToWithdrar'r;
nrAnountToWithdraw
Chapitre 14 : Ouand une classe n'est pas une classe: l'interface et la structure
n=
1;
ll \a dclaration
MyStruct
ns.n =
la
ms;
3;
/i
ms,d = 3,0;
I
//
I
un objet de classe
doit tre
a11ou
partir
MyClass mc
new MyClass;
mn n = ?.
mc.d = 2.0;
Figure 14.1
La variable
SITUCtUI mS
-rside" dans
1
I
la mme
zone de
mmoire que
3.0
la variable de
l-n
l.+ms
I
mc
Vt't-L
2
2.0
particulier
du tas.
347
296
De notre point de vue d'tre humain, la diffrence entre un four microondes et un four conventionnel ne semble pas de la plus haute importance,
mais envisagez un instant la question du point de vue du four. Les tapes
du processus interne mis en (Euvre par un four conventionnel sont compltement diffrentes de celles d'un four micro-ondes (sans parler d'un four
convection).
Le pouvoir du principe de I'hritage repose sur le fait qu'une sous-classe
n'est pas oblige d'hriter l'identique de toutes les mthodes de la classe de
base. Une sous-classe peut hriter de I'essence des mthodes de la classe de
base tout en ralisant une implmentation diffrente de leurs dtails.
Ce
-rf4k\
-6:
tl
S/
My0lass
I faire cuelcue
a---a
chose
i
public static void AFunction(int)
{
t r^:
^..^1-Ue
rda!e-^ qusrq
I t
ChOSe
d'aUtre
ll
Ghapitre 14 : 0uand une classe n'est pas une classe: l'interface et la structure
^59trK
,ffi \
\T /
"(
Bien qu'elle puisse retourner la valeur cle I'objet .sous forme i nr, il'.' , . l'1rne dit rien sur ce que contient la classe. La gnration cl'une valeur r :,i peut
trs bien mettre en jeu un calcul complexe.
La classe BaseClass implmente l'interface ICcnpare (la n-rthocle concrte
GetValue O retourne le membre donne nYalue). Toutefois, la mthocle
CornpareTo (1, qui est galement exige par I'interface l'l r:r.i,.-, i,," est dclare
-
t-
d.U>
- *,.
L ]
,
dL
L.
Dclarer une class abstract signifie qu'il s'agit d'un concept incomplet,
auquel manque I'implmentation d'une ou de plusieurs proprits (clans
ce cas, la mthode CorrrpareTo ( )).
Main() cre deux objets de la classe Sui,:Cl-a,,s:; avec cles valeurs cliffrentes. Elle passe ensuite des objets l'11'F unc ( ) . La mthode l'l'.,F.r:r
s'attend recevoir deux objets de I'interface I r.li,r.Dari:. i'1-,,l ir:r.- utilise la
mthode CompareTo O pour dcider quel objet est le plus grar-rd. pui.s
GetValue ( ) pour afficher la "valeur" des deux objets.
,
petir
que ic2
rerlesvariables.Lesvariablesd'untypevaleurCommeli,letl:l.:'
sont dclares et initialises d'une certaine rnanire
int
n=
'I
345
29 4
1e$!Qa"
a^w71-7 \
Le ramasse-miettes et le destructeur G#
La mthode du destructeur est beaucoup moins utif e en C#que dans d'autres f angages orients
objet, cCImme C++, car C# possde de ce I'on appelle une destruction non dterministe.
t# est non dterministe parce qu'il ne peut pas tre invoqu avant que
l'objetaitt rcupr parle ramasse-miettes, ce quipeutse produire longtemps aprs qu'if
Le destructeur de
a cess d'tre utilis. En fait, si le programme se termine avant que l'objet soit trouv par le
ramasse-miettes et retourn au tas, le destructeur n'est pas invoqu du tout,
Au bout du compte, l'effet qui en rsulte est qu'un programmeur C# ne peut pas se reposer
sur le destructeur pour oprer automatiquement comme dans un langage comme C++.
I Abstractlnterface -
^l -^^^
Lroc
^l^+-^)
ouo
u, ort
C,,^+^-.
"--i^^
u1116 uj
Lfl,
Abstractlnterface
namespace
I
//
ICornpare
public interface
.o '1rnr
a
P!vt,!
ICompare
rtelprrr
ICornparable
; -+L
f,tl
BaseClass
implmente
f interface
ICompare en
nrrh l 'i n
int
nValue;
public
(int nInitialValue)
BaseClass
i
nValue = nInitialValue;
]
//lt
II
public int
GetValue
return
nValue;
//
complte
eh<trrnf
quoLq!L
nrrhl.in
yuuraL
interface
jr+
rrrL
abstraite
l.nmaa-^T^/^h.innruLJtrrPdrtrru\uuJuL
rinlr+hi..nt\
rlrILvuJerLL/,
l
(rrhfll
/ /
ee -
1^ ^1
^ ho.o
..l1f ;- j -,
6.66n1+^
ctasse
oe
udse eli
^ ^.^
^. reuertlr,ssant
--...r1eLe ia
BaseClass
I
L
]
tI
^
uomparelo
orrprridp
vv!!ru
nrrhl
yuvarL
ic int
irrL
',n
^-^^
n',
riahthiant)
CnmnnrpTn(nhiont
vvrxyutrv\vuJsuL
trSrrLVUJrL/
BaseClass bc
= (Base0lass)right0bject;
343
292
nAccountNumber
= **nNextAccountNumber
nBalance = rnlniti-alBalance
l
I
mme
chose
ici
//
nrrhlin
r*-**,
{
// tnitSauinssAccount
'^"o-"-'--'."
- 1it le tarx rJ'intrt exnripf sp
I
pourcentage (valeur comprise entre 0 et 100)
public SavingsAccount(decimal mlnterestRate) : this(0, mlnterestRate)
I
l
^,.L1
yuurrLi
c-..-irrr6n\
-^^ ^:count
uqv
(decimal mlnitial ,
decimal mlnterestRate)
: base(minitial)
thi.s.mlnterestRate = mlnterestRate
tOO;
mme
chose
ici
l
hllhlr^
PUUTfL
l,^^,j1
Urdi
^l^FLJd
//
chcrrp
urrrYu
nrrhl i
decimal npay)
{
I
cre un compte bancaire et 1'affiche
BankAccount ba = new BankAccount(100);
DirectDeposit(sa,
100)
Accunulatelnterest ( ) ;
Console.Writeline("Compte [0J", sa.ToSavingsAccountString() ) ;
l/ attend confirmation de 1'utilisateur
Console.w*riteLine("Appuyez sur Entre pour terniner...") ;
sa.
Console.Read0;
return
l
]
0;
Chapitre 14 : Ouand une classe n'est pas une classe: l'interface et la structure
class BaseClass {}
class Subtlass : BaseClass {l
class C1ass1
{
l
]
Ici, un objet de la classe SubClas s put tre pass la place d'un objet
d'une classe de base, parce qu'une sous-classe EST_UNE classe de base.
Bird peut tre pass une mthode attendant un tableau d'objets IConparable, parce que Bird implmente cette
interface. L'appel suivant lisplayArray O passe le tableau birds, encore
une fois sans cast, parce que Bird implmente I'interface IDisplayabie.
De mme, un tableau d'objets
Tri
de
la liste
L1SA
: IUU
Marge
Bart
:50
Maggie
:30
Homer
:0
85
des tudiants
34 |
290
public class
BaseClass
public
BaseClass
()
public BaseClass(int i)
t
i)
Console.ItiriteLine("Construction de BaseClass([0])",
l
l
BaseClass
public
SubClass
()
Console.l^Iriteline("Construction
l
public SubClass(int
i
base(i1)
il,
i2);
]
]
public sratic
Console.Read0;
return
0;
l
]
l
Ce programme donne la sortie suivante
Invocation de Sub0lass 0
Construction de Base0lass (default)
Construction de SubClass (default)
Invocation de SubClass(1, 2)
..")
Ghapitre 14 : Ouand une classe n'est pas une classe: l'interface et la structure
return s;
]
]
--Birds - tri des oiseaux par non -l{ --I I Bird * tableau de noms d'oiseau
^-1^..^b1e
cl ass uaru
Bi rd .: rvvxrPdldUaE.
TComr:--^L1^ rn.:
Lf,qD
LUL>yLajdl
{
private string
sName;
student
this.
sName
sNane;
appelante
DLALTL
birds
Ii]
= new Bird
(sBirdNames
Ii]
return birds;
]
//
-..L1.ipuDl1C
^+-.i -Srrlng
[T^
Name
get
{
return
sName;
]
]
/itt
/l
II
implmente
Cornpareo
lrinterface IComparable
compare les noms des oiseaux, utilise
:
la
mthode de comparaison
339
288
dont elle ralise une extension. Il y a une raison cela : chaque classe est
responsable de ce qu'elle fait. Une sous-classe ne doit pas plus tre tenue
pour responsable de I'initialisation des membres de la classe de base
qu'une fonction extrieure quelconque. La classe BaseClass doit se voir
donner la possibilit de construire ses membres avant que les membres
de SubCias s aient la possibilit d'y accder.
urt
Qrra+nm
ujLrlr
namespaee Exanple
t
public class
C1ass1
scl =
ner,r SubClass0;
return
Read
0I
l
]
public class
BaseClass
public
BaseClass
public BaseClass(int i)
{
l
l
public class SubClass:
SaseClass
\vf
DisplayArray(birds);
ll attend confirmation de 1'utilisateur
Console.WriteLine("Appuyez sur Entre pour terminer..,")
Console.Read0;
l
/
| \:
^' 1 -"4 --^" - dLIILiIE
d'ohipts
nrri
!f,>Pr/ll)
affiche un
Ull tablearr
LdUfc@u
u vuJL
yur
inplmentent f interface lDisplayable
I
| |
nrrhlin
ct:tir
vnirl DicnlrrrArrev
(iDisplayable
{
I displayables)
.int
lpnoth:
___ _ _
___o ___ dr^-1-,.^L1^rrsplaya0res . T^-^*l
Lengrn;
for(int index = 0; index ( length; index**)
i
Console.l{riteLine(" i0J
l
l
]
ll ---- Students - trie 1es tudiants par moyenne de points d'UV ---// Student - description d'un tudiant avec son nom et ses points d'UV
class Student : IComparable, IDisplayable
{
orivate strins
r"'*
sName;
ll net de ct les
= sName;
donnes de
1'objet
this.sName
this.
dGrade
dGrade;
for (int i = 0; i (
sNames.Length; i++)
sArray
Ii]
lil ,
l
F^+1rFh
tgLuLll
^A--^,,,
drL4j/,
/l
dGrades
Ii]
337
286
o)
if (o is
MyClassl)
MyClassl mc1
(MyClass1)o;
1t
'T
l
'I
J
is
L'hritage et le constructeur
Le programme InheritanceEx:rmp1e que nous avons vu plus haut dans ce
chapitre repose sur ces horribles fonctions Init. . . pour initialiser les
objets BankAc(lounr et SavirrgsAccount en leur donnant un tat valide.
quiper ces classes de constructeurs est certainement la meilleure
manire de procder, mais elle introduit une petite complication.
//
II
I
lnheritingA0onstructor
using
System;
namespace
InheritingAConstructor
public class
t
Class1
nom
er ses points
d'UV
//
oublic dorrble
Grade
get
{
return
cjGrade;
//
II
ll
CompareTo
return
i
-1
if
{
rol-rrrn
I.
Llg!!l
return
0;
Le
[]
void MyFunction(student
un simple appel
students)
l0omparable
335
284
=f
stre que I'objet qui lui est pass est bien un Sa,,'i i'ssAccoun: avant
d'effectr-rer Ia conversion. C'est dans ce but que C# offre le rnot-cl j
-:.
L'oprateur is admet un objet sa gauche et un type sa droite. Il retourne true si le type I'excution de I'objet qui est sa gauche est
compatible avec le type qui est sa droite.
Vous pouvez modifier I'exemple prcdent pour viter I'erreur I'excu-
I
dpose une grosse somme sur le compte
bankAccount. Deposit ( 10000. 00) ;
1'objet est un SavingsAccount
I
(bankAccount i.s SavingsAccount)
I si
if
{
Accunulatelnterest ( ) ;
l
]
I
-..L1.:
^ LaL_LU
^+^+.1 ^ ..^..i
VUI_U
PUUr.r_U
TestCast
()
g1
I
L
return
dGrade:
]
]
I
I r^-o+-]
-^ - rtrrrn
unp
r LVU!rr
Ull
rro0rsentation
de 1'tudiant
Ug LO Ll Irr
-
I I
(
-',L1.1
GetStrino
^ D^+-1^4
L frrb
ve ev s rrtb | /)
PsurlL
return
int
length = displayables.Length;
for(int
index =
0;
index
length; index*+)
tI
l
Cette mthode D.spia;'rAr ray i, 1 peut afficher n'importe quel type de
tableau, condition que les rnembres du tableau dfinissent une mthode
GetStringt). Voici un exemple de sortie de Displai'Arra'y(; :
Homer
:0
Marge
:85
333
282
de faon ambigu, faire dmarrer une voiture n'est pas la mme chose que
faire dmarrer un moteur. L'opration dmarrage de la voiture clpend
videmment du dmarrage du moteur, mais ce sont cleux chose.s distinctes : il faut aussi passer la premire, lcher les freins, et ainsi de suite.
Plus encore, sans doute, faire hriter Ca: de i,|r,r-rl st une reprsentation
errone des choses. Une voiture n'est tout simplement pas un type
particulier de moteur.
L'lgance du logiciel est un but qui se passe de justification. Non seulement
elle le rend plus comprhensible, plus fiable et ais maintenir, mais elle
rjouit le gott et facilite la digestion, entre autres.
Autres considratons
C# implmente un ensemble de caractristiques conues pour supporter
I'hritage.
Changer de classe
Un programme peut changer la classe d'un objet. En fait, c'est une chose
que vous avez dj vue dans cet exemple. SomeFunction O peut passer un
SavingsAccount sa
ne!/ SavingsAccout 0
I
ot<:
sa =
sa
ba;
// Nonl
l/ 1a conversion vers
I I ceci est correcr
1e haut
(savingsAccount)ba;
SavinqsAccount.
crire
Tan+as
!oPLUP
., /r^-^,'+^vVtuPULtr!,
le
PDA
l
PUUfAU LIdUU
IRecordable
vvf,u
yu9ltL
^,,1-1.i ^ ,,^i,1
TakeANote
string
sNot
il
l
l
Chacune de ces trois classes hrite d'une classe de base cliffrente. mais
implmente la mme interface IRecirrilabie.
r$.;
nX
tI$,
Y
L'interface iil.e r.:y'(lab 1e indique que chacune cles trois classes peut tre
utilise pour crire une note en utilisant la mthode T,i.i..i ,.i,t . ftour
comprenclre I'trtilit de ce procd, voyez la fonction suivantet :
public class Class1
t
recordObject)
erer une
liste
de commissions
puis 1a noter
recordObject. TakeANote
slist)
PDA pda
new PDAO;
RecordShoppingList (pda)
33 |
280
et
100)
(BankAccount bankAccount,
dec irnal mlnt erestRate)
this.bankAccount = bankAccount ;
this,mln:erestRate : mlnterestRate
tOO;
// Accumulatelnterest -
invoque une
fois par
priode
bankAccount.mBalance = bankAccount,mBalance
t (bankAccount.mBalance * mlnterestRate)
mAmount)
i
bankAccount . Deposi.t (mAmount ) ;
j
i
I
I
I
Withdraw
return
l
]
La relation
A UN
I
cre un nouveau compte rmunr
BankAccount ba = nev BankAccount(J
SavingsAccount_ sa = new SavingsAccount*0;
sa. InitSavingsAccount
I et y
(ba,
.)
interface IRecordable
i
void TakeANote(String
sNote)
Rentarquer le rnot-cl inr erf a.ce la place de c1ass. Entre les accolades
se trouve urle liste de mthodes abstraites. Une interface ne contient
aucune dfinition de nrembre donne.
La rnthode Tal.re.l'loie O est crite sans implmentation. Les mots-cls
public et'.'r"-tr-ial ou a.Sstracr ne Sont pas ncessaires. Toutes les
mttrocles d'une interface sont publiques, et une interface n'entre pas en
jeu clans un hritage normal.
329
278
La proprit Balance permet de lire le solde, mais sans donner la possibilit de le modifier. La mthode Deposit O accepte tout dpt positif. La
mthode r^/ithd raw ( ) vous permet de retirer tout ce que vous voulez dans
la limite de ce que vous avez sur votre compte. ToBarrkAccor-intS -rir'g o
^e.St
7X
ttgrf
Y
- i'ai du nal
La relation EST UN
La relation EST_UN entre SavingsAccourlL et Bar,krrircounr est mise en
vidence par la modification suivante Classi dans le programme
SirnpleSa.,.ingsAccoLlni de la section prcdente
:
public class
C1ass1
t
L
// Direetltenos'i t - effectue
automat-i 0rement
Chapitre 14
structure
Dans ce chapitre :
Explorer la relarion PEUT_TRE_UTIUS_COMME.
Qu'e
276
ll
1)
InitBankAccount (0)
nAccountNunber = **nNextAccountNumber
mBalance * mlni-tialBalance;
// Balance (so1de)
tl
oublie deeimel
Balance
// DeOOsit
JL Ji.A+
UCyVL n^..i+'if
tr
- tor'+
^st autoris
PVfLfr
--r---
mArnount)
if
(mAmount
0)
nBalance *= mAnount;
]
]
//
||
Wittdrar,I
if
(mBalance
(-
$lJithdrawal)
nlrlithdrawal = nBalance
mBalance -- ntrli"thdrawal
return mWithdrawal;
]
I J q^<+-:^
rvuL!rrr
tt
public string
uet le
return String.Format("{0i
nAccountNunber, mBalance)
[1:CJ",
;
l
I
SavingsAccount
compte bancaire
BankAccount
/l
II
- lit
et
100)
? 32 5
O,,^+^*,
D Ltrlu.
oy
public class
BankAccount
/l
II
Withdrawal
dt/ithdraw)
)")
BankAccount
of"j
)")
i
]
SavingsAccount
l,lriteline
("
invoque
Spec
)"
l
Ce fragment de code
'SoecialSaleAccorrnt'
classe
sce11e'SavingsAccount'
274
ftemarquez que la proprit EST_UN n'est pas rffexive: un Student EST_UNE person,
mais I'inverse n'est pas vrai. Une Person N'EST_PAS_UN Student. Un nonc comme
celui-ci se rfre toujours au cas gnral. ll pourrait se trouver qu'une Person particulire
soit effectivement un Student, mais beaucoup de gens qui sont membres de la classe
Person ne sont pas membres de la classe Student. En outre,la classe Student possde
des proprits qu'elle ne partage pas avec la classe Pe rs on. Par exemple, un Student a une
moyenne de points d'UV, mais une Person ordinaire n'en a pas.
L'hritage est une proprit transitive. Par exemple, si je dfinis une nouvelle classe
de Student, alors un Graduatestudent est
aussi urt Person. Et ildoit en tre ainsi ;si un Graduatestudent EST*UN Student et un
Student EST*UN Person, alors un GraduateStudent EST-UNE person, C0FD.
]
l
//
I
SaleSpecialCustomer
- compte utilis
i
cverri.de public void liithdraw(double dWithdrawal)
{
Console. lrlriteLine
("
appelle SaleSpecialCustomer.Withdraw()");
l
]
ll
]
Chacune de ces classes tend la classe qui se trouve au-dessus. RemarqUeZ tOutefoiS que Si-.e.:lai-Salel'r:.LruLr. i^,:it-horali() a t marqUe
une srie cle mthocles Test (1, dont chacune est conue pour accepter
une sous-classe diffrente. Chacune de ces versions de Test () appelle
Iwithdra-; ( I clans la perspective d'un objet de classe diffrent.
La sortie cle ce programme se prsente de la faon suivante
d'un BankAccount
p,^f rrcr Test (BankACcOUnt) \
appelle BankAccount . Withdraw ( )
Passage
nnttr pff
r uu
L \yg4rr!rr!uvqrr
L /
Pncs:op
_-_*D_ d- rfin
_-. sn..i--^^^^^..-!
_*vflrl1uLUultL
norrr pffpct,ror Test (BankAccount)
_
appel
1e SavingsAccount
v urr
L /
Withdraror
()
()
? 323
272
Les langages orients obiet expriment cette relation d'hritage en permettant une classe d'hriter d'une autre. C'est cette caractristique qui
permet aux langages orients objet de produire des modles plus Proches
du monde rel que les langages qui ne disposent pas du principe de
I'hritage.
/l
tnheritanceExample
- offre la
dnionstration
1^
.i--1^
l^
Id -1.,^
Pfu> bJilurtr u lrhr.i
-.------o-t:op
using
Systern;
^ Ufd
^1-^^ D-"eC1ass
-..L1.:
u
PUU.LfU
{
in ini
nrrhf
y|\vLLv
nflnl4lvlenbef
nuhlic void
SomeMethod0
l
nrrhlic class SubClass
BaseClass
n'h1in'rnil
VVrU
PUUTTL
(nmo0thorMpthodfl
lrlvs\/
UVI.vv
Conso1e.l,lriteline ("SoneOtherMethod
")
]
nrrhlin
nlecc'l'oql
1;
bc.nDataMenber
bc, SomeMethod0 ;
erons naintenant un 1ment d'une sous -classe
ll
:");
#"u$3
l_frrl,i
// tnheritanceTest
examine comment
narrf
ycuL
.,''
fra
sL!c
rrtiljc
uLrrtrE
le
mot-c1
n^'r.
yvu!
virtual
lih^ts
ldIM!
using Systen;
public static
/''\
'Iest.t tDaj
lestt
<f
(sa,/
Test2 (sa)
Testl (ssa)
lesIz tssa/
^/
lest3 (ssa)
//
;
;
Console. 1{riteline ( ) ;
Console. 1,lriteLine ( "Hit Appuyez
Consol,e. Read
return
0;
l
public static void Testl
(BankAccount account)
32
27 0
Par exemple, seule une mthode dfinie dans le mme espace de nom que
BankAccount peut crer un objet tsank.,rccount avec Ie constructeur
dclar comme internal (pour en savoir plus sur les espaces de nom,
reportez-vous au Chapitre l6) :
i/
BankAccount
public class
- simule un simple
compte bancaire
BankAccount
double dBalance;
i/ invoque 1e constructeur spcifique en fournissant
I I des valeurs par dfaut pour 1es arguments nanquants
internal
BankAccount
{)
nAccountNumber
dBalance 0:
= **nNextAccountNumber
( ctri nd
nrrhl i n rrn'i d Otrtnrrt
LyuL
\oLrarr
une chane
en11+hr1(+
vuLyuLULrfrr6/'
ri..
'
//
SubClassl
- inplmentation concrte
de AbstractBaseClass
ctrino
c = cSr1rcp ToTTnnpr{l'
!
'
rvuytJ
u!
\ /
'
[0]",
s)
]
]
l/
SubClass2
*"L1';^ Lro
c"Lnlass2 : AbstractBase0lass
^1^^^ uuuuJ
de AbstractBaseClass
l,uurr
{
strins
- -- -"o s = sSource.ToloverO;
Console.l,./riteLine("Appe1 SubClass2,0utput0 depuis
{0}",
s)
class Classi
t
ba)
ba.0utput("Test");
l
// et enfin un objet
Subclass2
/
lesr (scrl
l
= new SubClass2 0
Read
..") ;
?3|I
C#
."u3
,\
Ha;'l
I
] \.Y
public class
C1ass1
StreanWriter
string
srd
sFileName
= nul1:
r'rr '
vhile (true)
{
try
{
//
= Console.Readline0
(sFileName.Length *= 0)
sFileName
if
t
I
break:
]
//
/l
II
II
II
II
II
II
II
I|
II
397
35
'l'^\trlnl
il111nl1tF11nat1^n
vuLPu
{ll}"
tvr
ll.
]
no - fnrrrnit
luJ L! -r-llt
ruul^^- rrno c'imnlo fnnnt'inn
I//I tnStri
Tn(trinof)
nrrorridp nrrhl in ctrino
u Lt frr6
rvu Lt arr6 \,/
r1o t\;n
-,,- -ctr'
-- 1fl8
Extrait directement *
C#
Les classes d'l/O sont dcrites dans I'espace de nom S1-stem. r,-. La classe
de base des I/O de fichier est FileSrrean. Autrefois. le programmeur
ouvrait un fichier. La commande c.pen prparait le fichier et retournait un
handle. En gnral, ce handle n'tait rien de plus qu'un numro d'identification. Chaque fois qu'on voulait faire une opration de lecture ou d'criture sur ce fichier, il fallait prsenter ce numro.
C# utilise une approche plus intuitive. Il associe chaque fichier un objet
.s\)G /
Fr
leSirean n'est pas la seule classe qui peut effectuer des oprations d'l/O
Hsurdesfichiers,maisc,eStbienellequireprsentenotrebonvieuxfichier
t\9,
Y
de base, qui correspond 90 %, de nos besoins d'l/O sur les fichiers. C'est la
classe racine qui est dcrite dans cette section. Si elle est satisfaisante pour
C#, elle I'est aussi pour moi.
Fi leS i- re:rir, est une classe trs basique. Ouvrir un fichier, fermer un
fichier, lire un bloc et crire un bloc, c'est peu prs tout ce qu'elle vous
donne. Heureusement, I'espace de nom -Svsten.IO contient un ensemble
de classes qui compltent FileS ti aiir pour vous donner un accs plus
facile aux fichiers. et un sentiment de confort douillet
:
Fea 1r- :. , i .-L. riteEinar r' : Ce sont deux classes de flux qui contiennent des mthodes permettant de lire et d'crire tous les types
valeur : FeadCrLar (), riteChar O, ReadB.,'t-e O, i^lriteBl''te O, et
"i
pour crire un objet en format binaire (non
ainsi de suite. C'est utile
lisible par un tre humain).
-.
r'e
anil i^, i. -o :
,/
t/
39 5
35
exemple, ini- n'est que I'autre nom de la structure int3 2, double est I'autre
nom de la structure flor,ib-re, et ainsi de suite. Le Tableau 14.1 donne la liste
complte des types et leur nom de structure correspondant.
Nom de structure
bool
llcolearr
byt
l-.+,-.
sbyte
decimal
r
Decinai
double
Doub I
float
int
Singie
Int32
ui nt
UInt-12
cha
P,',-: e
Cha
T-+
I Li I U A
ong
ong
Uint64
ohicet
.-"J---
0b-ject
short
Int 16
Uinr,6
u1
usho
rt
n'St que I'autre nom cle la structure Int32. Comme toutes les structures
d'Cb,j ect, lnt doit en driver comme les autres. Cela conduit
quelques rsultats fascinants, comme le montre le programme suivant :
drivent
i
I
I
I
TypeUnification
using
int et Int32
fait la nme chose
montre comnent
sont en
System;
namespace
{
TypeUnification
rraurqPaLc
G#
nLLtr
^^^^';sControlLib
..^.i*^
utrrrB C,,^+^-,
JyLtrnr,
public class
Cl.ass2
public void
A_pub1ic
t
Console
i,iriteline
nrnientcd
Console,
i{riteline
("
Clas
s2.
B_protect
ed "
Console
l,'/riteline
("
Clas
2 . C*pri-vate "
internal
voi-d D internal o
Console
'i-+^--^1
-"otected
rlr
Ltrr rrar yr
void E internalorotectedo
E_internalprotected" ) ;
t/
t/
t/
correct.
393
35
t.N =
newValue;
Test. D
]
/
I
dNewValue;
j nn
/ 0r:tnrrtl'rrnnt
oui
imolmente
vsLPu
LrrvuL
- aff iche toute mthode
Yur
ToString0
yUUalL
LdLIL
)]rtn]ltF11nal'1nl
VUaU vuLyu
I lllcnlr\rrhl
\re+VroJaur
1d
ru/
Console. WriteLine
(r'id =
{0} "
id. ToString 0 ) ;
l
S'- r ric i-.rr eEx.rnpi e dfinit tout d'abord une interface,
IL)ispia',.a'1, e, puis une simple structure, Tes*., eui implmente cette
interface. T'es'- clfinit galemer-rt deux membres:un membre instance,
et un membre statique, .r. Un initialiseur statique assigne la valeur 20
Toutefois, le rnembre instance ii n'a pas droit un initialiseur.
Le programme
n,
d.
t dfinit
(),
I'interface i D i s p 1 a-v-ab I e.
La fonction i'Ia,;; ( ) met Te s | l'preuve. Tout d'abord, elle cre un objet
test dans Ia rnmoire locale, et utilise le constructeur pour initialiser cet
espace.
I'objet.
L'appel
Cha:rger.i
C#
*e"*lil
l-----H:\;ir
?,-J
//
II
AccessControl
fornes
de contrle d'accs
nnespce AccessControl
{
using
System;
using AccessControllib
Class2
public static
int Main(string[]
strings)
ll
II
l
;
les
I
Llo4
^ In
puuffL
/\
\,,r
'
c1ass1 . B*protected
travers
i /c1ass3 . B-protected ( ) ;
I 7es rnthodes prives ne
39 |
350
.rflkc
%H\
=\S\f )
\-/
//
I
structureExample
using
using
System;
System. Collections;
namespace StructureExample
{
string ToString0;
j
I
I
II
I
private int n;
private static double d = 20.0;
I/
ll
on peut
les
utiliser
un constructeur pour
nembres donne
initialiser
d'une struct
publi"c Test(int n)
{
this.n = n;
l
public int
get { return n;
set { n : value;
J
l
public static double
{
get
{ return d; l
set { d = value;
i
C#
namespace
Paint
{
L
nmesnce MnthRoutines
IL
public class
Test
args)
r
t
I
I
Sort obj =
new Sort 0 ;
obj . SoneFunct ion ( ) ;
ll cre un objet dans un autre espace de nom, renarquez que
ll Ie non de 1'espace de nom doit figurer explicitement dans toute
I I rf.rence de classe
J
1
J
Dans ce cas, les deux class Sort et Test sont contenues dans le mme
espace de nom, l/iat.hRcul-ines, bien qu'elles apparaissent dans des
dclarations diffrentes dans le module.
fonctior 'ie..:t . i"lair' ( r peut rfrencer la classe Sort sans spcifier I'espace
de nom parce que les deux classes sont dans le mme espace de nom. Toute
fois, Liain O doit spcifier I'espace de nom Pa in-, quand elle se rfre
l'ai n',Co'or, comme dans I'appel Paiir'- . PalltCo Lor . StaticPalnr (1.
La
Remarquez que vous n'avez pas besoin de prendre des prcautions spciales
en vous rfrant ir,ark. Paint 0 , parce que la classe et I'espace de nom de
I'clbjet b iai:k sont connus.
389
3 48
ne,,v
(une fois
MyClass
t
urc
nc[0] .n = 0;
Ce tableau est galernent un gros consomrnateur de ressources, de temps
comme d'espace. Tout d'abord, chaque lment du tableau mc doit tre
assez vaste pour contenir une rfrence un objet. En outre, chaque
objet MyCiass fait une consornmation invisible de ressources au-dessus
et au-del du ser-rl rnembre donne n. Enfin, il y a le temps que prend le
programme pollr effer:tuer toutes les manceuvres ncessaires afin de
rduire cent fois cle suite un petit bloc de mmoire.
La mmoire clestine aux objets de type structure est alloue en tant que
partie du tableau :
ll
.i*+
i^+^-^-^ = IlW .:-+
rrrL fl
int f1n^l
Ll rrrL!r
[100]
integers lOl = O;
ll La dclaration d'un tableau de struct est tout aussi sinple
Mrr(trrnt[1 .o = new MyStructitO0];
rvLLl
ms[0]
.n
.av
0;
Le constructeur de structure
Une structure peut tre initialise en utilisant une syntaxe semblable
celle des classes, ce qui est intressant :
public struct MyStruct
I
t
hllhl1^
thf
MyStruct ms
n.
* new MyStruct 0
C#
Un fichier de projef contient des instructiorrs sur les fichiers qui constituent
le projet et la manire dont il.s se combinent.
Vous pouvez combiner des fichiers de projet pour produire des combinaisons
de programlne qui dpendent des rnmes classes dfinies par I'utilisateur.
Par exemple, vous pouvez vouloir associer un programme d'criture avec le
programme de lecture correspondant. De cette manire, si I'un des deux
change, I'autre est automatiquement rgnr. L'un des projets dcrirait le
programme d'criture, et I'autre clcrirait le programme de lecture. On appelle
solution un ensemble de fichiers de projet.
.a\\G
-UnprogrammeurVisuaIC#utilisel'ExplorateurdeVisualStudiopour
fl?It
\7
387
346
MyClass
public int
n;
l
MyClass mc;
lul{J
rrew, M,,a1^^
r'tyurass \,)
La structure C#
C# clfinit un troisime type de variable, appel une sfructure, qui comble
le foss entre les types rfrence et les types valeur.
La syntaxe d'une dclaration de structure ressemble celle d'une classe
nrrhlin
'i
nt n,
public double
d;
public class
MyClass
nrrhli^
yuuarL
nrrhl 'i
'irrrL
n+
ul
n'
rrt
nrrhl o d.
l
On accde un objet structure comme un objet cle classe, mais I'allocation est identique celle d'un type valeur :
Chapitre 16
344
]
htthl'^
yuuIfL
f'rF^l
ura
Laa
^l^
public static
t
Console,Read
return
0;
//
II
ll
tt
lI
string
1 . GetValue (
ic
2 . GetValue ( )
s;
switch (ic1,
CompareTo(ic2)
case
0l
break;
'
case -1:
s = rrest plus
petit
que";
break;
case
1:
break;
default r
s * "quelque chose qui cloche";
break;
l
Console
l,lriteline
Abstractlnterface
simple.
L'interface IConpare dcrit une classe qui peut comparer deux objets et
aller chercher leur valeur. ICompare hrite de I'interface IConparal-t:
rt9{Qa. Le processeur Intel retourne effectivement une valeur pour 1.0/0.0 : Irrf iniry.
existe plusieurs valeurs spciales en virgule flottante pour traiter de tels cas
^v7q \ Ilplutt
:(dq9
que d'envoyer une exception, car tous les langages n'ont pas la capacit
)
\/
de traiter cles exceptions. Parmi ces valeurs spciales, ily a I'infini positif et
ngatif, et le s),mbole iJaii Q,lot-a-Number - pas un nombre) positif et ngatif.
Dans les circonstances normales, la mthode In.,rerse i ) retourne le
rsultat attendu. Quand on lui passe une valeur nulle, cette mthode aux
ides larges envoie une CustomException, passant une chalne d'explications avec I'objet fautif.
Travaillant I'envers, Main () attrape I'exception, puis affiche un bref message destin expliquer o en est le message dans son traitement : "Erreur
f atale inc onnue" signifie probablement que le programme est sur le point
de fermer boutique et de rentrer chez lui. Main O donne ensuite I'exception
la possibilit de s'expliquer en invoquant sa mthode ToStrlng O. ffoyez
l'encadr "ToStringQ, la carte de visite de la classe" dans ce chapitre.)
Comme dans ce cas I'objet exception est effectivement un
Cu s tornEv-c epr- I on, le contrle passe Cus t ornExc ept i on . To S t ring ( ) .
Cette mthode T'oStrirrg O affiche le message de I'exception avec la
mthode cible initiale et le numro de ligne correspondant.
ToSt'ring O d'un objet que vous devez compter pour crer une version
st ring de celui-ci, plutt que d'essayer d'accder I'objet lui-mme pour
en extraire Ies valeurs afficher.
383
3 42
Tri de la
Alouette
liste
des oiseaux
Corbeau
tourneau
Grive
Hirond el I e
Tourterelle
Vautour
Appuyez
Les tudiants et les oiseaux sont tris, dans la logique de leurs catgories
respectives.
Hritage et interface
Une interface peut "hriter" des mthodes d'une autre interface. Je mets
des guillemets autour clu rnot hriter, parce qu'il ne s'agit pas d'un vritable hritage, mnre s'il en a pourtant I'air :
IConpare
-a
// getValue - rerourne
int GetValue 0
int
usLng Systen;
namespace CustonException
{
Excepti.on
nathobject =
sMessage
mo;
sMsg;
Message
(+"ina
Fara+/rtT^!
uLL1116tru!ltroL\
petf rpttrrn
6Lr!sLurrr
jllcbSd8e
-ao-^^^
gbL
^.-
lInl\
\tuJ
/,
lrnh jat
- _-L
oqt
string s =
Message;
s *= "\nException
s *= TargetSite;
envoye par";
rt1rrn c.
//
II
MathClass
public class
- collection de fonctions
mathnatiques
int
nValue)
nValue0f0bject = nValue;
s0bjeetDescription : sDescription;
]
public
//
II
int
l{essage
l'objet
public string
de
Math0lass attach
Message
get
{
l
]
// ToString -
combj.ne 1e nessage
personnalis avec
[]Jrl
38 |
3 40
]
I I :*^1
r-^-+^-+
| |
lurPfErurrLsrrL
| i-+^-f^^^
1
r
lrrL!lLE
1n.i.^1
ayrPro)
^Vab1e
return
liane;
l
]
La class Student (elle est peu prs au milieu de ce listing) implmente les
interfaces ICornparabie et IDispl ar.able que nous avons dcrites plus haut.
ConpareTo O compare les tudiants par "grade", ce qui a pour consquence
que les tudiants sont tris par grade. GetString O retourne le nom et le
grade de l'tudiant.
Parmi les autres mthodes de Stu'lent, il y a les proprits en lecture seule
et Grade, un constructeur simple, et une mthode CreateStudentlist ().
Cette dernire retourne simplement une liste fixe d'tudiants (au dpart, j'avais
pens permettre I'utilisateur d'entrer au clavier les noms des tudiants, mais
le listing devenait si gros qu'on n'y voyait plus I'essentiel).
Name
-sq4k
P-/ j5: \
V '
les autres chapitres (en particulier ceux du Chapitre 6). Ceux-ci sont
des tableaux d'objets d'une classe particulire, par exemple un tableau
d'objets Srudenr, alors que conf.,ar-abieCrbi ec+;s est un tableau d'objets
qui implrnentent I'interface ICoinparable, indpendamment de la classe
laquelle ils appartiennent.
Le tableau conparabief l-,-ject-c est pass la mthode Array . Sor: | ), qui
en trie les lments sur la base clu grade.
n'rhli^
"^.i'1 f1 /)
!r
vvrs
\/
try
t
f20;
l
I I attrape une erreur
catch(MyException ne)
{
. traite
..
Console
l
l
exception :
public void fl o
try
{
t20;
l
t
I | . . . traite une partie de l'erreur
Console.l.lrireLine ("Exception attrape dansfl () ")
poursuite du cheninement de l'exception
ll .
+1^-^,,.
Llltuw
37I
338
public string
Nane
of
D''
{
rt1r rn sNemo
l
nrrhlic dorrhle
Grade
ger
{
return
dGrade;
l
l
//
implmente
f interface
I0omparable
(nnc. e o
| vvruyeriu
anraraTn - LvltrHat
nrrtro
nh-iet
o rrn
ull
auL!
vLi
_^^rqnrr
|| |
I
II
II
I
,^aa.
et dcide lequel
dans le
tableau tri
I conoare
Student courant (aooelons-le
--J
- -1'obiet
I 'celui de gauche' ) 1 tautre student (appelons - 1e
ll 'celui de droite'), et gnre une erreur si aucun des deux
// n'est un obiet Student
Student leftStudent = this;
(
:r
^1^+L..i^^t is student))
ar \; | t-:
\!rrrLwuJcu
I
I
Console
l,lriteLine
("I"Ithode de conparaison
return 0;
I
I
if
/
leftStudenr.grade)
leftStudent.Grade)
rotrrrn
-1.
if
(rightStudent.Grade
return
1;
return
0;
]
l l inpTnentent
f interface IDisplayable :
// GetString - retourne une reprsentati.on de 1'tudiant
Console.Read0;
<ttr
Fnt ro
rnttr
f40
+arminor
Une fonction comme f2 ( ) n'attrape qu'un seul type d'exception. Elle recherche
une certaine classe d'erreurs. Par exemple, l"fyException peut faire partie des
37 7
336
Comparez cet exemple t'algorithme de tri du Chapitre 6. L'implmentation de cet algorithme demandait pas mal cle travail et ncessitait beaucoup de code. Il est vrai que rien ne vous garantit que Ai'ra.,i. Sor:r | ) est
meilleur ou plus rapide que cet algorithme. Il est seulement plus facile.
Assembler le tout
Voil le moment que vous attendiez tous : le prograrnme Sc,r.i Inte r-t'a c e
complet, construit en utilisant ce que nous avons dcrit plus haut dans ce
chapitre
using
System;
nanespace
Sortlnterface
lui-mme en
I
'i
ntprf :no
Ti-l'i
c.1 ayable
string GetString0;
class C1ass1
{
7e tableau
[] comparableObjects
Array. Sort (comparable0bjects) ;
IComparable
II
(IComparable [] ) students;
IDisplayable
DisplayArray (displayable0bjects ) ;
doigts
using
name
System;
Exception
base(sMsg)
nyobject
mo;
try
{
f2 (bExceptionType)
catch(Exception e)
t
)")
37 5
33 4
Bart
Lisa
Maggie
lYrv-
fr-(
llr9r,
Y
:50
:100
:30
,/
Que c'est beau ! Voyez comme les rsultats sont aligns sur les noms
complts par des espaces pour faire tous la mme longueur.
Interfaces t rdfinies
De mme, vous trouverez dans la bibliothque stanclard de C# des interfaces intgres en abondance. Par exemple, I'interface IComparabie est
dfinie de la faon suivante :
interface
IComparable
1es autres cs
si vous voulez savoir comment une chaine peut tre "plus grande" qu,une
autre, voyez le Chapitre 9.
N'y voyez aucune intention darwinienne, mais vous pouvez dire qu'un
objet Student est "plus grancl" qu'un autre objet Student si sa moyenne
de points d'uv (grade point average) est plus grande. c'est soit un tudiant plus brillant, soit un meilreur courtisan, peu importe.
ll
objects)
catch
SorneFunction0
try
{
Some0therFunction
]
catch(MyException
me)
l
i
Et si SomeOtherFunction O avait envoy une simple Exception ou une
exception d'un type autre que Mylxc eption ? Autant essayer d'attraper
un ballon de football avec un filet papillon. Le catch ne correspond pas
I'envoi. Heureusement, C# permet au programme de dfinir toutes
sortes d'instructions catch, selon le type d'exception attraper.
Les instructions catch doivent figurer I'une aprs I'autre aprs le bloc
try, de la plus spcifique la plus gnrale. C# teste chaque bloc catch
en comparant squentiellement les objets envoys au type d'argument de
I'instruction catch.
public void SoneFunction0
i
Lrrtty
+
{
SomeOtherFunction
catch(MyException
me)
i/
ici
37 3
332
Je veux
-^
interface IDisplayable
{
string GetString0;
'1
Name
get
{
return
sName:
l
]
Idisplayable
Le reste de cette sortie est ce que I'on appelle une indication de pile (stack
trace). La premire ligne de I'indication de pile indique I'endroit partir
duquel I'exception a t envoye. Dans ce cas : Factorial (int ) (plus
prcisment, la ligne 23 du fichier source C1ass1 . cs. Factorial ( ), ou la
ligne 52 du mme fichier, a t invoque dans la fonction Main (strlng IJ ).
L'indication de pile s'arrte I'tain ( ), parce que c'est le module dans lequel
I'exception a t attrape.
rr|r
t\\u--
.1
L'indicationdepileestdisponibledansl'unedesfentresdudbogueur
If Cff I
Y
16.
Exception
private Mvclasss
,,1::i':::.
base(sMsg)
{
tyob3'..a = *0,
//
public
37 I
330
t_
^$sq
7X
tsp,
Y
nlncc
PDA: IRecordable
il
string
fait
..*-'1.-.Ycuelsue
sNote)
la
note
l
]
sNote)
l
PUUJr-U UJ-dbb
PDA
: ElectronicDevice,
(string
sNote)
IRecordable
nValue);
I I
do
{
dFactorial *=
nValue;
] while ( - -nValue ) l)
// retourne 1a valeur stocke dans 1'accumulateur
;
return dFactorial;
]
try
{
de 6 -6
catch(Exception e)
f
]
]
369
32 8
ob
jer
Je peux donc dire que ces trois objets (le stylo, le PDA et I'ordinateur
portable) implmentent I'opration TakeAlJote. En utilisant la magie de
I'hritage, je pourrais implmenter la chose en C#, de la faon.suivante
nh<f
rrnt
nrrhl
'i
n "oid
TakeANOte
(string
SNOte)
ThingsThatRecord
i
]
public class
PDA
ThingsThatRecord
pDA
ThingsThatRecord
]
-rl
>7V
Ifcilt
l\zt
\
Cette solution reposant sur I'hritage semble fonctionner trs bien pour
ce qui ne concerne que I'opration TakeAl{ote O. Une fonction comme
RecordTask O peut utiliser la mthode TakeANote O pour noter une liste
de commissions sans se soucier du type d'appareil utilis :
void RecordTask(ThingshatRecord thi.ngs)
{
1es classes
t/
Ces problmes ne paraissent pas si graves dans cet exemple simple, mais
ils ne font qu'empirer avec la complexification du code de Ia fonction
urrv
\ /
/l
ceci est
fait
try
II
I
SomeOtherFunction ( )
ll
catch(Exception
e)
l
l
nrrhf
PueffL
i
|
in vnid Ss6sQtherFUnCtiOn0
l'erreur se produit
quelque
part
dans 1a fonction
36 7
326
i = 6, factorielle
1 = ), tactorl.el_le
i = 4, factorielle
-i = I
i
i
fentnriallo
= 2, factorielle
- 1, factorielle
- tzv
- rlv
:6
-L
-1
1 = u, racl0r1elle -U
lactoriaL 0 a reu un nombre ngatif
Appuyez sur Entre nntrr torminor
L'indication d'une condition d'erreur I'aide d'une valeur retourne par une
fonction n'est autre que la manire dont le traitement d'erreur a toujours
t ralis depuis les premiers jours de FORTRAN. Pourquoi changer ?
/e
Quel est I'inconvnient de retourner des codes d'erreur ? C'tait trs bien
pour FORTRAN ! C'est vrai, mais cette poque les tubes vide taient
aussi trs bien pour les ordinateurs. Malheureusement, I'approche des
codes d'erreur prsente plusieurs inconvnients.
1t$Qa"
{cg)
Bien que I'on puisse contourner ce problme en utilisant la valeur retourne par une fonction pour une indication d'erreur et un argument de type
out pour retourner une donne, cette solution est moins intuitive et fait
perdre une partie de la nature expressive d'une fonction. Quoi qu'il en
soit, lorsque que vous aurez vu comment fonctionnent les exceptions,
vous vous dbarrasserez bien vite de cette ide.
36 5
32 4
appelle SavingsAccount.Withdraw( )
pour effectuer Test (SpecialSaleAccount)
appelle SpecialSaleAccount. Withdraw ( )
Passage d'un SaleSpecialCustomer
pour effectuer Test (BankAccount)
Wi
thdraw
Sa1 e S pe c
ia1 Cust
ome
r . l,lithd
rar,r ( )
Appuyez sur Entre pour terminer... J'ai mis en gras les appels clui prsentent un intrt particulier. Les classes tsankAcccuni t
Sa.;ir,gsAccount fonctionnent exactement comme on peut I'attendre.
Toutefois, en appelant Test (Sa,,'ings.Account ), SreciaiSa lesA.:i:ount t
SaieSpecialCurri-rn: se passent eux-mmes corlme un
SavirrgsAc.orlnt. Ce n'est qu'en regardant le niveau immdiatement
infrieur que la nouvelle hirarchie Sa-cSlecialC'rsr.,.riili peut tre
utilise la place de SpeclalSale:cc,ir-'..
? Le
polymorphisme n'est-
dit, un programme que j'cris peut utiliser directement des classes venant de dpts
accessibles par Internet.
Je peux donc tendre une classe que j'ai tlcharge sur Internet. La redfinition
des
mthodes d'une hira rc hie de c la sses sta nda rd, teste, peut avoir des effets q u i n'taient pas
voulus. L'tablissement d'une nouvelle hirarchie de classes permet mon programme de
bnficier du polymorphisme sans risque de briser le code existant.
public class
MyMathFunctions
fournie
dValue)
// interdit les
if (dValue ( 0)
nombres
ngatifs
return
NEGATIVE_NUMBER
return
N0N_INTEGER_VAIUE
I par 1a valeur
obtenue
do
{
dFactorial *= dValue;
dValue -= 1.0;
I while(dValue ) l);
// retourne 1a valeur stocke dans
1'accumulateur
return dFactorial;
l
h'!hlr^
yuurrL
^t^^^
Lld
/uI4D
t^d^1
// calcule la factorielle
du nombre
if (dEactorial
== MyMathFunctions.NEGATIVE-
NUMBER)
I
Console
}trriteLine
chaque
fois
363
32 2
Console.Writeline
account . l,lithdraw
( 1 00) ;
l
public static void Test2(SavingsAccount
account)
]
nrrbl
ir" stat'i c
vo'i
Tpsf
Console,WriteLine
l
public static void Test4(SaleSpecialcustomer
account)
00)
//
II
II
BankAccount
possdant
publie class
BankAccount
il
Withdrar,'ral
Withdraw(double dWithdraw)
Console.Writeline(" appelle
BankAccount.Withdraw()")
//
SavingsAccount
compte bancaire
BankAccount
Console.i,{riteline(" appelle
SavingsAccount.Withdraw0")
nrrhf
{
new
Withdraw(double dWithdrarral)
II
rnnol I e on
uvuaE^
|/ |I ofyf,rL
rr hnrrnl
1a fonction Factorial de 6 -6
for(inti=6;i)
1--
t
I
passage
i,
MyMathFunctions.Factorial (i) ) ;
')
J
Console.Read0;
factorielle = 72A
factorielle = i20
factori.elle = 24
factorielle = 6
factorielle = 2
factorielle = 1
factorielle = 0
factorielle = factorielle = -2
factorielle = -3
factorielle = -4
factorielle = -5
1
Un simple coup d'il avis ces rsultats permet de voir qu'ils n'ont
aucun sens. Pour commencer, le rsultat d'une factorielle ne peut pas tre
36t
320
TEST
\---Il
\Y'
-
Chapitre 15
Ouelques exceptions
d'exception
Dans ce chaptre :
e sais que c'est difficile accepter, mais il arrive qu'une mthode (ou
une fonction) ne fasse pas ce qu'elle est cense faire. Mme celles que
j'cris (surtout celles que j'cris) ne font pas toujours ce qu'elles doivent
faire. Il est notoire que les utilisateurs aussi ne sont pas fiables. II suffit que
vous demandiez un int pour qu'il y en ait un qui entre une chane de caractres. Parfois, une mthode poursuit son chemin joyeusement, ignorant
voluptueusement qu'elle est en train de produire n'importe quoi. Il y a
toutefois de bons programmeurs qui crivent leurs fonctions de manire
anticiper sur les problmes et les signaler lorsqu'ils se produisent.
Je parle ici des erreurs I'excution, et non cles erreurs de compilation
f
"9tt$
ilfi ) qu" C# vous envoie la tte lorsque vous essayez de gnrer votre
,
U-/ Programme.
C#
YK
e,
Placez toutes les fonctions d'l/O dans un bloc i-r-i.avec une instructiotr caT-r.r.r
qui gnre un message d'erreur appropri. Il est gnralement considr de
mauvaise pratique de gnrer un message d'erreur inappropri.
La boucle whi 1e srt deux choses diffrentes. Tout d'abord. elle perrnet au
programme de revenir en arrire et d'essayer nouveau en cas d'chec d'une
llO.Par exemple, si le programme ne trouve pas un fichier que I'utilisateur
peut lire, il peut demander nouveau le nom du fichier pour tre str de ce
t/
tz
3I I
C#
fichier que vous avez entr (lath est une classe conue pour manipuler
des informations sur les chemins d'accs).
Le chemin d'ctccs (path) est le nom complet du dossier dans lequel se
trouve le fichier. Dans le nom de fichier complet c:\user\tenD
dlreC*rct'1.\tex',.lxt, le chemin d'accs est la partie c:\user\i,i-lr
oireC*;orv.
.
1e$!Qa.
^.v7q
=qE/
puis encore
Entrez un nom de
fichier
Entrez un non de
fichier
40 I
C#
break;
ll
\
nrl.n l,r)F.Ynn11
\-----'-r --' on Iel
{
Console
I,]riteline
" {0J
\n\n" , fe.
Message)
fichier :")
try
t
I
1:- ..-^
| l-J.L
Urltr f1.:--:
fBrrt 1a fOiS
I I
r,vhile
(true)
I lit
une ligne
=:
T tStnnllr
nul_LJ
break;
l
ll crit
Console
sur la console ce
LIriteline ( slnput
l
l
catch (l0Exception fe)
{
I
I
*sisnale
I artreoe toute erreur de lecture/criture et- la
"*b..*-(ce aui fait aussi sortir de 1a boucle)
l
I
I
I
I
fini
avec 1ui
try
{
sr.
C1ose
catch i l
// attend confirnation de 1'utilisateur
Console.I,lriteLine("Appuyez sur Entre pour terminer. . .")
Console.Read0;
403
C#
Readline O. Le programme affiche cette ligne sur Ia console avec I'omniprsent appel Coirsole. i,JrlteLi:icr (t avant de revenir au dbut de la
boucle pour lire une autre ligne cle texte. L'appel F eaC'iiie ( ; retourne un
nu11 lorsque le programme atteint la fin du fichier. Quand cela se produit,
le programme sort de la boucle de lecture, ferme I'objet, et se termine.
Remarquez comment I'appel cicse (, est insr dans son propre petit
bloc try. Une instruction caici, sans arguments attrape tout ce qui passe
sa porte. Toute erreur envoye par C,cse L, est attrape et ignore.
L'instruction catch est l pour empcher I'exception de se propager vers
le haut de la chalne et d'arrter I'excution du programme. L'erreur est
ignore parce que le programme ne peut rien faire en cas cle 1,,,.-sil
invalide, et parce qu'il va de toute faon se termir-rer la ligne suivante.
.$sC ,. Je ne donne I'exemple de catch sans arguments qu' des fins de clmonsHtration.Laprsenced,unseulappeldansSonproprebloc'iaVeCune
instruction carcfi "attrape-tout" vite qu'un programme s'arrte cause
tt9,
Y
d'une erreur sans importance. N'utilisez toutefois cette technique que
pour une erreur vraiment sans importance, ne pouvant causer aucun
dommage.
Entrez le
nom
Could not
find fi1e
Entrez 1e
nom
Contenu du
,Te
tane
"C:
\C#Prosrams\FileRead\TestFilex.txtr'
fichier
lire:TeslFilel.txt
Et onnnro nn
Et
a\
""'*-r-r" c nr.r
Y*
-" nrri
Annrrrroz <rrr Fnfro nnrrr term'inpr
TestFilel . txt
=(t
^*\
lte.
40 5
Ginquime partie
Programmerpour
Wi ndowsavecVisual
Studio
Chapitre 17
et le plumage
Dans ce chapitre :
3.
description du problme.
La conception d'une grande application doit tre dfinie dans les
Concetur la prsentaton
SimpleEditor est un diteur, et c'est un diteur simple, Il doit avoir une
grande fentre dans laquelle I'utilisateur peut entrer du texte. Comme
cette fentre est la partie la plus importante cle n'importe quel diteur,
elle doit occuper pratiquement tout l'cran.
Toute application Windows ncessite un menu Fichier, imrndiatement
suivi sa droite par un rnenu clition. Les autres lments de la barre cle
menus dpendent de I'application. sauf pour I'aide qui en est le clernier.
Dans le menu Fichier, il nous faut un moyen d'ouwir un fichier (Fichier/Ouvrir),
un moyen d'enregistrer un fichier (Fichier/Enregistrer), et un moyen de sortir
(Fichier/Quitter). Le petit bouton de fermeture dans le coin suprieur droit de
la fentre doit avoir le mme effet que Fichier/Quitter. Nous n'avons pas besoin
d'une commande Fichier/Fermer. C'est trs joli, mais comme nous n'en avons
pas besoin, c'est une chose que nous pouvons garder pour la version 2.
4l I
Comme je I'expliquerai dans les sections qui suivent, ces tapes ne sont
pas mal faites si vous les suivez I'une aprs I'autre.
l.
Slectionnez Fichier/Nouveau/Projet.
La fentre Nouveau projet apparalt.
2.
Au lieu de I'icne Application console, cliquez sur I'icne Apptication Windows, et entrez comme nom SimpleEditor.
Dans la fentre Nouveau projet, le champ Emplacement spcifie le
rpertoire dans lequel seront stocks les fichiers de SimpleEditor.
Autrement dit, Visual Studio va mettre tous les fichiers que je vais
-grfl(c
-i: \
-.-/
=( fA )
\t/
3.
Ei(htr/ Edilr
.!' -L'-t
I i!.
EO
::'::
l -' '!'
?i"ffi,,:li#"i:'l;|,t2,';',. -inl:J
tigure 17.2:
L'affic h age
initial pour
toutes les
applications
Windows.
rm8ordr5i/
5,rable
FqhtToLeft
li.
Ir--t
ina,."r.
t.,:.1
AIc\4tro!
::t te lW,
nnd
ImetlDde
B t;tytt :, ...
FisF
l3qrri
t te
l,n:!nt.r
.
Ei iorEniPnpr'
Ie*
LE
lexind6u
&ffiGcdrdt
4l3
Avant d'aller plus loin, je veux jeter un coup d'il au code C# gnr par
le Concepteur. Je veux savoir ce qui se trame l-dedans. L'Explorateur de
solutions montre que le fichier source de ce programme se trouve dans
un fichier nomm F,.--rm1. c:s, ce qui correspond au nom qui se trouve audessus du formulaire dans la fentre du Concepteur.
Slectionnez Affichage/Code pour faire apparaltre une nouvelle fentre
contenant le code source C# de F o rin I . .' -c, que voici
:
.'^"i-^
urrr
C,,a+^-.
eJLEur,
using System.Drawing;
using Systern. Collections
using System, ComponentModel
using System.Windows . Forms;
using System.Data;
;
nanespace SimpleEditor
{
//l
(sumnary)
/i/
III
III
(sunmary)
(lsmnary\
private System.
public Forml 0
ConponentModel,
lt
/
lt
tt
Required
for
InitializeConponent
lt
i
lt
l
lll
kunnary)
II
I
III
(lsumary)
if(
disposing
if
f
(conponents != nu11)
4l 5
4t6
components.Dispose0;
l
l
cnncin-rrI
heca
D'i cnnco (\ rli
v4s . urDyvoc
uIDyu
I
,,
.
t
I
///
III
lll
(sunrnary)
//
For:nt
this.AutoScaleBaseSize
this.ClientSize =
this.Name
this.Text
= "Forml";
"Sirnple Editor";
///
III
lll
(summary)
ISTAThread]
static void
Main0
Annl
4ytl!rLo
inatinn
rrvtl
.
i/\
Rln /nor.,
.l\ulr
I'^rml
ulIlI
\rrgw
\ / ,/ ,
'
str
1e${Qa. En fait, Application. Run O lance I'objet Form sur son propre thread
7^l \ d'excution. Le thread initial s'arrte aussitt que le nouveau Forml est
=lf \ff / cr. Le thread Fornl se poursuit jusqu' ce qu'il soit intentionnellement
Y,/ arrt. Le programme SirnpleEditor lui-mme poursuit son excution
aussi longtemps que des threads dfinis par I'utilisateur sont actifs.
Le constructeur de Formi invoque une mthode InitializeComponent O.
Tout code d'initialisation du programmeur doit tre plac aprs cet appel
(tout au moins, c'est ce que dit Ie commentaire).
4l 4
4.
5.
6.
Figure 17.3
Changer la
proprit
-Text du
formulaire
change le
nom qui
a ppa rat
oans sa
barre de titre.
4l 2
Itla soluton
Avec les paramtre.s que j'ai dcrits dans la section prcdente, je suis
arriv la solution montre par la Figure 17.1. Vos propres rsultats
peuvent tre diffrents selon vos gotts personnels.
W:"
-lol
Fichier Edition
r:I
Frrrt
t{J
p trI: t -'rn
=rl
lus grand
Figure 17.1
Ma solution
du problme
:
-SinpleEditor.
ralb
s-
'Je
police
jf-
)|
14
Dessner la soluton
Comme vous pouvez I'imaginer, j'ai dt passer par de nombreuses tapes
pour arriver en partant de zro l'uvre d'art montre par la Figure 17.1.
4l 0
t/
t/
t/
t/
t/
Erposer le problme
Chaque fois que vous tes devant un problme rsoudre, vous devez
commencer par vous mettre devant le tableau noir et rflchir srieusement aux obstacles franchir. Dans le cas d'une application Windows,
cette tche se divise en trois tapes :
l.
"*
40 4
Filel^i
rite.
t/
t/
partir de ce
.ssG ./
Hdesexceptionsdefichier.VouspouVeZinsrertoutleprogramrrrede
traitement de fichier dans un mme bloc rr-,,, comme dans Fi le,.,r rte, ou
tTg,
bien vous pouvez donner son propre bloc I r_,. la section d'ouverture de
fichier. Cette dernire solution est gnralement la plus facile, et elle
permet de gnrer un message d'erreur plus prcis.
Une fois le processus d'ouverture de fichier termin, le programme
FileRead lit une ligne de texte dans le fichier en utilisant I'appel
402
.,:
.' r .
C"^+^*.
uJ
Lclr
rrc"ino
*- "'^b
Svctonr
irtucy4Lg
0'
f -Lgr\u
vaq
^ ..^ ,'.ss]
yuufrL
tra
l/ i1
nous
streamReaoer sr;
-strins sF:leName
= "";
"'"
ii continue essayer de lire un noin de fichier jusqu' ce qu'il
// trcuve un (1a seule naaire de quitter pour I'utiiisateur est
I I d'arrter 1e programne en appuyant sur Ctrl + C)
en
while {true)
t
f-- r\rJ
i
I I Iit le non du fichier d'entre
Console,Write("Entrez le nom d'un
sFileName
= Console. Readline 0
throw
rLew
fichier vide");
FileAccess . Read) ;
400
,/
Le type d'accs : Un fichier peut tre ouvert pour la lecture, l'criture ou les deux.
^1'sC
Hpondpardfautunoucleuxclesargumentsdemodeetd'accs.Toutefois, mon humble avis, il vaut mieux spcifier explicitement ces arguments, car ils ont un effet important sur le programme.
t(9,
Y
("
miner I'encodage.
^rv7q
:/dqf,
v,/
t.iriteLine ( ) et Console
b'
sw . C1o
e()
.t^i
riteLine
39 8
I
|
ob
jet
FileAccess.Write,
FileAccess.ReadWrite
FileStream
fs = File.0pen (sFileName,
FileMode . CreateNew,
FileAccess.l.rlrite) ;
// gnre un flux de fichier avec des caractres UTFS
sw = new StreamWriter (fs , System. Text , Encoding. UTIB) ;
I I lit une chalne 1a fois, et envoie chacune au
// FileStrean ouvert pour criture
Console.l'lriteLine("Entrez du texte ; ligne blanche pour arrter");
while (true)
{
break;
lue
l,friteLine ( slnput ) ;
l
I
I ferne 1e fj-chier
sl^r. C1ose
sw
= null;
i
catch(IOException fe)
i
,:
Console
Writeline (fe
Message)
]
]
I
. . ")
39 6
ob
jet
Avec C#, les classes de System. r0 supportent galement les f/0 asynchrones. En les
utilisant, l'appel read ( ) restitue immdiatement le contrle pour permettre au programme
de poursuivre son excution pendant que la requte d'l/0 est satisfaite I'arrire-plan. Le
pr0gramme est libre de vrifier l'tat d'un indicateur pour savoir s1 la requte d'l/0 a abouti.
C'est un peu comme de faire cuire un hamburger. Avec des l/0 synchrones vous mettez la viande
hache cuire sur la plaque chauffante, vous la surveillez jusqu' ce qu'elle soit cuite, et c'est
seulement partir de l que v0us pouvez vous mettre couper les oignons qui vont aller dessus.
Avec des l/0 asynch rones, voLrs p0uvez couper les oignons pendant q ue la viande hache est
en train de cuire. De temps en temps, vous jetez un coup d'il pour voir si elle est cuite. Le
momentvenu, v0us abandonnez un instantvos oignons, etvous prenez la viande sur la plaque
chauffante pour la mettre sur le pain.
Utilser S t
i:"
r-r
ili,{r i t e r
sortie est trtile porrr stocker cles objets cl'urie nranire efficace.
Beattcoup cle pro{tar}}ines, sirron la plupart. liseni r:t crivent des chalnes cle
texte, lisibles par ult :tre lrurrrairr. Les classes cle flux Sr: eai:l,,rrirer et
StrcanP,e,:;,.r,1,-:r s()ut les plus souples cles classes arccueillantes pour I'homnte.
Ae/'!-t\
:(dqfl
\/
des
chalnes ASCII, ou, i.rrI peu plus tarc1, NSL Ces deux sigles se rfrent aux
organisati<lns cle stanciardisation tlrri ont rlfiiri c:es formats. Toutefois, le
codage ANSI lte pennet 1r;ts cl'inttigrer les alphabets venant de plu.s loin
que l'Autriclre l't-st, et tie plir.s loin que [{arvai' I'Or:e.st. Il ne peut contenir que I'allrhabett latin. Il ne clispose pas de I'alphabet r:yrillique, hbreu,
39 4
t/
Une mthode dclare internal est accessible par toutes les classes
du mme espace de nom. Aussi, I'appel class2. D internal O n'est
pas autoris. L'appel cl ass3. c internal O est autoris parce que
Ciass3 fait partie de I'espace de nom AccessControl.
t/
t/
ir iernal
DLofecleJ.
C1ass2.A-public
Class2.B_protected
C1ass1.C-private
C1ass3.D_internal
C1ass2
C1ass3
E*internalprotected
E_internalprotected
sur Entre pour terminer...
Appuyez
rsq- I
lX
[f9,
Y
Dclarez toujours les mthodes avec un accs aussi restreint que possible. Une mthode prive peut tre modifie volont sans inquiter de
I'effet que cela pourrait avoir sur d'autres classes. Une classe ou une
mthode interne de Ma thRoutines est utilis par d'autres classes de
nature mathmatique. Si vous n'tes pas convaincu de la sagesse du
couplage faible entre les classes, allez voir le Chapitre 1 1.
392
| la
mme
classe
C-private ()
c1ass1.C-private0 ;
I I class2.
I
I
I I c|ass2. D-internal ( ) ;
c1ass3.D -internal 0 ;
I I es mthodes internes protges
sont accessibles
que par
par
1/\
uons0ie. Kea0
return
0;
l
-r,hr-^
yuurru
(,r
,r^rd
vvfu
/\
|w_y!
--lvatel/
!riteline ( "Class
Console,
1,
C-private" ) ;
l
j
I
I
nrntpntpd
y!vLLLu
vnid
B nrotectpdo
rlv!s\/
vvru
internal
voi.d D-internal o
t
Console . 1,,Iriteline
("
Class3 . D*internal" )
l
^,rhlin
yuurJL
u_frr
v vfu
LvL
uee
\ /
Console
|jritel,ine
"C1ass 3 . E-internalprotected"
39 0
,-i
namespace Paint
{
i
namespac
llathP.out ines
I
/
using Paint;
public class Test
{
static public
t
voj.d
Main(stringll
args)
b1ack. Pai.;.t ()
PaintColor, StaricPaint 0
l
La courrnancle ..,r i r. ,, rlit : ' Si volls ne trouvez pas ia c'lasse spcifie dans
I'espace d' rrorn courant. voyez si vous la trouvez (lans celui-ci." Vot.ls
pouvez spcifier arrtarrt tl'espaces cle norn que vous voulez, mais toutes
les cornrnanrlc-s ',r.r , - ; cloivent apparaltre I'une aprs I'autre tout fait au
dbut clu pr()qrallll].
9i51
I(Bfl
\SZl
-
;,ir
r i :',:
r-
388
GtLi
,,i
-il,
L
-I-
class MyClass {i
class UrClass {J
l
etl
I r ;,.,,s
l'{ySruff.
,,s$G t
L'Assistant Application de Visual Stuclio place chaque classe qu'il cre dans
HuneSpaCeclenomportantlemrnenOmquelerpertoirequ'ilcre.Exami-
t\7,
V
nez tous les programmes cle ce livre : ils ont tous ts crs I'aide de
I'Assistant Application. Par exemple, le programnle AliqnOutput a t cr
dans le dossier --t1!.ni;u-f lrL1*.. Le nom du fichier source est Class i . cs, qui
corresponcl au nom de la classe par dfaut. Le nom de I'espace de nom dans
lequel se trouve Class l . t-:: est le mme que celui du dossier:Ai,gnoLitpl-1...
votre
classe dans I'espace de norn global. C'est I'espace de nom de base pour
tous les autres espaces de nom.
namespace MathRoutines
t
class Sort
{
public void
SomeFunction0
{l
386
ne peut pas tre modifi par deux programmeurs en mme temps. Chacun
d'eux a besoin de son propre fichier source. Enfin, la compilation d'un
module de grande taille peut prendre beaucoup de temps (on peut toujours
aller prendre un caf, mais il arrive un moment o votre patron devient
t/
Un fichier source ne peut tre modifi que par une seule personne la
fois. Vous pouvez avoir vingt trente programmeurs travaillant en
mme temps sur un grand projet. Un seul fichier pour vingtquatre
programmeurs impliquerait que chacun d'eux ne pourrait travailler
qu'une heure par jour, supposer qu'ils se relaient vingtquatre heures
sur vingtquatre. Sivous divisiez le programme en vingtquatre fichiers,
il serait possible, bien que difficile, que tous les programmeurs travaillent en mme temps. Mais sivous divisez le programme de telle
manire que chaque classe a son propre fichier, I'orchestration du
travail de ces vingtquatre programmeurs devient beaucoup plus facile.
,/
t/
La rgnration complte d'un grand programme comme un systme de rservation de billets d'avion peut prendre beaucoup de
temps. Vous n'aurez certainement pas envie de rgnrer toutes les
instructions qui composent le systme simplement parce qu'un
programmeur a modifi une seule ligne. Avec un programme divis
en plusieurs fichiers, Visual Studio peut rgnrer uniquement le
fichier modifi, et rassembler ensuite tous les fichiers objet.
38 4
(Value = 0)
Jetons un coup d'il cette sortie : le message lifc,,.ir faia L.r i rc.or.nue : vient de l'{a: i-' i l. La chane -,t n's'r- -.il'. ( -in:ossi l-,-i-' r,l 'in
,,.erser 0,\, I'c,l iet esi <--) vient de ilu.-"t,-.11E:tcLrti.l. Le message
Value 0 vient cle I'objet l"1ai-irCiass lui-mme. La dernire ligne, Excep
tion en.".ove parDouble In'rerse, vient de C,-Lsl-r,'t:Fl,ce 'rti cn.
questions d'hritage, mais le principe est le mme. Par exemple, une mthode
382
le
//
Inverse
lix
retourne
if (nValue0fObiect ::
0)
0", this)
'I
try
t
I I prend f inverse de 0
MathClass math0bject = new MathClass("Va1eur", 0);
catch (Exception e)
t
//
l
]
380
Renvoyer le mme objet exception prsente un avantage et un inconvnient. Cela permet aux fonctions interrncliaires d'attraper des exceptions
pour librer ou fermer des lments allous par elles, tout en permettant
I'utilisateur final de I'objet exception de suivre I'indication de pile
jusqu' Ia source de I'exception. Toutefois, une fonction intermdiaire ne
peut pas (ou ne doit pas) ajouter des informations supplmentaires
I'exception en la modifiant avant de la renvover.
Exception
private
MyClasss myobject;
base(sMsg)
nyobjec-u = moi
]
ll
/
I
II
i
CustomException
affiche
37 8
eption.
f\
e,
q/\
vous ne savez pas quoi faire avec une exception, laissez-la passer poLlr
qu'elle arrive la fonction appelante. Mais soyez honnte avec vous-mme :
ne laissez pas passer une exception parce (lue vous n'avez simplernent pas
le courage d'crire le code de traitement cl'erreur correspondant.
Si
Relancer un objet
Dans certains cas, une mthocle ne peut pas traiter entirement une
erreur, mais ne veut pas laisser passer I'excepti<)n sans y mettre son grain
de sel. C'est comme une fonction mathmatique qui appelle:a.i )rral ,)
pour s'apercevoir qu'elle renvoie une exception. Mnte si la cause premire du problme peut tre une donne incorrecte. la fonction rnathmatique est peut-tre en mesure de fournir des indications supplmentaires sur ce qui s'est pass.
Un bloc catch peut digrer partiellement I'exception envoye et ignorer le
reste. Ce n'est pas ce qu'il y a de plus beau, mais a existe.
L'interception d'une exception d'erreur est une chose trs courante pour
les mthodes qui allouent des lments. Par exemple, imaginez une
mthode F O qui ouvre un fichier quand elle est invoque, et le referme
quand elle se termine. Quelque part dans le cours de son excution, F ()
invoque G O . Une exception envoye de G ( I passerait directement
travers r ( ) sans lui laisser la moindre chance cle fermer le fichier. Celui-ci
resterait donc ouvert jusqu' ce que le programme lui-mme se termine.
Une solution idale serait que F r ) contienne un bloc catch qui ferrne les
fichiers ouverts. Bien entendu, F O est libre de passer I'exception au
niveau suprieur aprs en avoir fait ce qu'il fallait pour ce qui la concerne.
Il y a deux manires de renvoyer une erreur. La premire consiste
envoyer une deuxime exception, avec les mmes informations ou ventuellement des informations supplmentaires :
37 6
Console.
Writeline
(e. Message)
]
I
I tZ ' -
f?/h^^1
!'
bExceptionType)
^,,11.i^',^;,r
VVaU
\wvv
PUUIrL
{
t rrt
i
f? thFvnant; ^.Type)
rJ
\vu.r!vyL4vrrr
catch (MvExceotion
me)
Console
l
l
I I tl - - n'essayez pas d'attraper des exceptions
publ1c vold tJ(00o1 D.Lxceptlontype/
f4 (bExcepti.onType)
]
I
I t+ - - envoie
bExceptionType)
I
nous travaillons avec un
MyClass mc = new MyClass0;
if (bExceptionType)
{
objet
1oca1
l
throw new Exception ( "Exception gnrique envoye dans f4 ( ) " ) ;
]
(true)
374
l
catch (Exception e)
{
ici
instructions quelconques . ..
Af\
=(t
tout
gnrale
public void
SomeFunction0
try
{
SomeOtherFunction{);
l
catch (Exception
me)
// tous
ici
l
catch(MyException e)
{
I
I
I
I
l
]
Dans cet exemple, I'instruction catch la plus gnrale coupe I'herbe sous
le pied de Ia suivante en interceptant tous les envois.
37 2
(lrs*:rr:l,li!t'-,i''
1,
et nlet en utilisation
try
{
SomeOtherFunction ( )
I
autres oPrations.
l
catch (MyExcePtion
me)
strj.ng s = me.ToString0;
I I nais vous vez aussi accs toutes 1es proprits et
// de votre pr0pre classe d'exceptions
nTthodes
MyClass mo = me.MYCustom0bject;
I I par eremple, denandez 1'objet MyClass de
lui-mme
s'affi-cher
string s = mo'GetDescriPtionO;
]
cratian de mYobject
= ner^r MyClass0;
signale une erreur concernant myobject
MyClass myobject
I
se sert de la toute nouvelle classe l'l'u.E:;cepti:'tr, pour envoyer non seulement un message cl'erreur, mais aussi I'objet 11'\rrb -i ec t fautif
SomeF
unction
( ,r
37 0
1t$\a.
S/^1 \
=(!,\7 f
Y'/
Cotnme l'Iairi ir est le point cle clpart clu programme, il est bon de toujours
en placer le contetru clans un bloc t r ,-. Toute exception qui ne sera pas
"attrape" ailleurs renrontera finalernent jr-rsqu' I'lain ( r . C'est clonc votre
fLapropritE>lile.1l1-t-.l..'l],':]:,.:1;l.retOurnleunSouS-enSemblepluslisible,
J-^t
mais moins descriptif cles informations sur I'erreur.
Ilorf
Y
i = 6, factorielle : 720
i = 5, factorielle = 120
1=
4. factorieTTe = 24
i = 3, factorielle = 6
i = 2, factorielle = 2
i = 1, factorielle :
i * 0, factorielle = 0
1
Erreur fatale
Appuyez
-1.
368
suite de 1a fonction
La fonction SoneFunction O contient un bloc de code identifi par le motcl try. Toute fonction appele dans ce bloc, ou toute fonction qui I'ap-
try.
Un bloc Lr.,r est immdiatement suivi par le mot-cl catcl-r, lequel est suivi
par un bloc auquel le contrle est pass si une erreur se produit en un
endroit quelconque dans le bloc try. L'argument pass au bloc catch est
un objet de la classe Exception ou d'une sous-classe de celle-ci.
un endroit quelconque dans les profoncleurs cle SomeOtherFunction O,
une erreur se produit. Toujours prte, la fonction signale une erreur
I'excution en envoyant (throv;) un objet Frception u premier bloc pour
que celui-ci I'attrape (catch).
_-"-ffi
using
System;
namespace
FactorialException
i/
ll
MyMathfunctions
collection de fonctions
mathmatiques
public class
l'lyMathFunctions
// lactorial II
retourne
fournie
la factorielle
d'une valeur
nValue)
//
string s = String.Forrnat(
"Argument ngatif
illicite
pass
Factorial {0J",
366
d'erreur que la fonction appelante ne teste pas. Bien str, en tant que programmeur en chef, je peux me laisser aller profrer des menaces. Je me souviens
d'avoir lu toutes sortes de liwes de programmation regorgeant de menaces de
bannissement du syndicat des programmeurs pour ceux qui ne s'occupent pas
des codes d'erreur, mais tout bon programmeur FORTRAN sait bien qu'un
Iangage ne peut obliger personne vrifier quoi que ce soit, et que, trs
souvent, ces vrifications ne sont pas faites.
Souvent, mme si je vrifie I'indication d'erreur retourne par Fa: r .r i '.I
ou par toute autre fonction, la fonction appelante ne peut rien faire d'autre
que de signaler I'erreur. Le problme est que la fonction appelante est
oblige de tester toutes les erreurs possibles retournes par toutes les
fonctions qu'elle appelle. Bien vite, le code commence avoir cette allure l
r
errRtn = someFuncO;
if (errRtn == SE*ERR0R1)
{
return
MY_ERROR_1;
if (errRtn == SF-ERROR2)
{
return
My_ERROR,2;
l
I
appelle SomeOtherFunetions,
errRtn : some0therFunc0
if (errRtn == S0F*ERRORI)
1it 1'erreur,
Console.l,lriteLine("Erreur de type
return
MY*ERROR-3;
if
(errRtn == SOF-ERROR2)
Console.liriteline("Erreur de type
return MY_ERROR_4;
)
t/
t/
36 4
if
(dFactorial =: l4vMathl'unctions
\eL
ev
ev
++
--J
NON*INTEGER*VALUE)
Console.
I^Iriteline
non
entier");
break;
]
i, MyMathFunctions.Factorial(i)
1
J
//
Console.l^lriteLine("Appuyez
Console.Read{);
de tests. Le
parce qu'il
(0
est
accept
passe
ngative
est
premier regarde si la valeur
son code ou qui I'utilise. Pour rendre un peu pius parlante I'erreur retourne,
la classe t4yMarhFirncl, ions clfinit deux constantes entires. La constante
NEGATIVE_|JUi'{BER reoit la valeur -1, et NOI'I IhITEGER VALUE reoit la valeur
-2. Cela ne change rien, mais I'utilisation des constantes rend le programme
beaucoup plus lisible, en particulier la fonction appelante Maln O.
Dans la convention sur les noms Southern Naming Convention, les noms des
constantes sont entirement en majuscules, les mots tant spars par un tiret
de soulignement. Certains programmeurs, plus libraux, refusent de faire
allgeance, mais Ce n'est pas la Convention qui a des chances de changer.
362
^"ffi
=(dg,
Les rsultats incorrects retourns ici sont assez subtils par rapport ce qui
aurait pu se produire. Si la boucle de Factc,r'iai O avait t crite sous la
forme do i . . . I whiie (dValue l: 0), le programme se serait plant en
passant un nombre ngatif. Bien str, je n'aurais jamais crit une condition
comme,"hile (dValue !: 0), car les erreurs dues I'approximation
auraient pu faire chouer de toute faon la comparaison avec zro.
Le programme
ncessaires :
C.,^+
^- ,
Jy b Lsnl,
nalnespace FactorialErrorReturn
{
li
II
Myl"lathFunctions
collection de fonctions
mathrnatiques
36 0
ob
jet
dis bien jamais.' si vous n'avez pas I'intention de dboguer vos programmes et si vous ne vous souciez pas qu'ils marchent, alors seulement c'est
peut-tre une bclnne ide.
Le programnle !'ar:'-or i alErrcr suivant montre ce qui arrive quand les
erreurs ne sont pas cltectes. Ce programme calcule et affiche la fonction
factorielle pour de nombreuses valeurs, dont certaines sont tout juste licites.
I
I
II
Factorial}JithError
crer et
using
utiliser
une fonction
aucune
System;
nnespace FactorialWithError
t
//
I
Uyttathfunctions
collection de fonctions
nathmatiques
public class
MyMathFunctions
i/
I
Factorial
I
I
norr
mrrl
ti nlier
'accumulateur
do
t
dFactorial *= dValue;
dValue -= 1.0;
J while(dValue ) 1);
// retourne la valeur stocke dans 1'accumulateur
return dFactorial;
l
]
trwr-d.55.1.
t^ddI
\-r-d.t'U
^t^dd
^rrhli^
PUUr.r-U
{
4t6
components.Dispose ( )
l
haee
urDyvrrri
\ ,lian^ain.
Di(b^<(
---
).
,/
'
//
Formt
this. ClientSize =
( 292
this.Nane = t'Fornl";
273)
///
III
lll
I
(summary)
stlthread
static void
Main0
Annl i eeti on
Rrrn
(new Forml
))
^tK
'(dE,)
Application.
Run
Initiali
zeComonent
).
Tout code d'initialisation du programmeur doit tre plac aprs cet appel
(tout au moins, c'est ce que dit le commentaire).
Ghapitre 20
e langage C# est assez largement bas sur C++. Cela n'a rien d'tonnant,
puisque Microsoft avait dj fait Visual C++, qui a t le langage de
C# n'est pas une couche de peinture sur une carcasse rouille. Il comporte
de nombreuses amliorations, la fois par I'ajout de nouvelles fonctionnalits et par le remplacement de fonctionnalits dj satisfaisantes par de
meilleures. Voici les dix meilleures amliorations de C# par rapport C++.
4|4
-K
=($9,
4.
5.
6.
W
Figure 17.3
Changer la
proprit
1'-^xt 0U
formulaire
change le
nom qui
a ppa rat
dans sa
barre de titre.
t/
t/
Me
l'Ie
d)
tement implmentes.
1e$\a"
\
^v7q
=(&"*.
t/
t/
if
avec un
47t
4|2
Ila
soluton
Avec les paramtres que j'ai dcrits dans la section prcdente, je suis
arriv la solution montre par la Figure 17.1. Vos propres rsultats
peuvent tre diffrents selon vos gotts personnels.
wf#ij
Figure 17.1
Ma solution
du problme
SimpleEdi:or.
,d-l-
Talle,3e police
{*
24
Dessner la solution
Comme vous pouvez I'imaginer, j'ai d passer par de nombreuses tapes
pour arriver en partant de zro l'uvre d'art montre par la Figure 17.1.
Ghapitre
as e c I as s N am e. m eth o dN atn
e'
Avec ce message, C# vous dit que vous avez surcharg une mthode dans
une classe de base sans la redfinir par une mthode qui la cache (voyez le
Chapitre 13 pour en savoir plus ce sujet). Regardez I'exemple suivant :
public class
BaseClass
l
nublic class Sub0lass:
BaseClass
l
l
public class
MyClass
sb.Function0;
]
'l
J
t/
BaseClass
469
4l 0
.)
Il rn'a fallu une longue et clifficile rflexion (au rnoins un quart cl'heure)
pour imaginer un problme qui mette en lumire la puissance de C# sans
me faire prendre du poids. Le voici : crer un cliteur simple que nous
appellerons Sinp-eEd ir ,r. Il aura les caractristiques suivantes:
t/
t/
lrLl
t/
,/
,/
Exposer le problme
Chaque fois que vous tes devant un problme rsoudre, vous devez
commencer par vous mettre devant le tableau noir et rflchir srieusement aux obstacles franchir. Dans le cas cl'une apltlication Windows,
cette tche se divise en trois tapes :
l.
Par dfaut, un membre d'une classe est';l'l-,,.ate, et une classe est internal.
Aussi, nPrivateMember est toujours priv dans I'exemple suivant :
class
MyClass
public void
SomeFunction0
l
]
public class
YourClass
int
nPrivateMenber
: 0; //
MyClass
nrrhlic
yqurru
rrn'i
qrr! L*vrr
Y vv d SomrrE'rrnntinn(l
uwu!
\ /
{
Irt
tl t
Some0therFunction
(out n) ;
int
n)
que dans
t+67
o.
float fResult = 2 * f;
return fResult;
]
La constante 2 est cle type in*-. Un int multipli par un f -:ar clonne un
f 1oat, qui peut tre stock dans la variable fResu;t-, de type f l,,r:rf .
Le message d'erreur de conversion implicite peut aussi apparaltre lorsque
vous effectuez des oprations sur des types "rlon naturels". Par exernple,
vous ne pouvez pas additionner deux variables de type char, mais C# peut
convertir pour vous une variable de type char en une valeur de type i:ri_
lorsque c'est ncessaire pour raliser I'opration. Ce qui conduit ceci :
class
MyClass
SomeFunctiono
char c1 = ta';
char c2 = 'b';
// ie ne sai s mme ns c nrrp npr.i oourrait vouloir dire ; c'est illicite
ll
neis nc n1lr
1.,*-
*a ra]-son
1
char c3 = c1 * c2;
]
Aclditionner deux caractres n'a en soi aucun sens, mais C# essair: quancl
mme. Comme I'addition n'est pas dfinie pour le type rlra r, il convertit
c 1 et c 2 en valeurs j nt vc lesquelles il effectue I'addition. Malheureusement, la valeur lrit Qui en rsulte ne peut pas tre convertie nouveau en
type char sans intervention extrieure.
La plupart des conversions, mais pas toutes, se passent trs bien avec un
cast explicite. La fonction suivante fonctionne sans se plaindre :
class
MyClass
t
I
cecz fonctionne
465
cf oii
n nlhl
S)
e/
: r * s.sStudentName)
d'identification de 1'tudiant = " *
Console.Writeline("Nom de 1'tudiant
Console.WriteLine("Nunro
s.nTd);
Le problme est ici que I'l7F:rnc tion i ) fait rfrence un membre donne
nlct au lieu du vritable membre donne nrD. Vous voyez la ressenlblance,
mais C# ne Ia voit pas. Le programmeur a crit nId, mais il n'y a pas de rrld,
MyClass
int
nCount
0;
while (true)
{
I tit
un nonbre
string s = Console.Readline0l
int n = Int32.Parse(s);
//rt quitte si 1'utilisateur
if(n(0)
break;
l
I
nSun
nCount#;
1
J
t
)
463
40 4
t/
partir de ce
F.e'acj,'ir
it...
L'objet FileStream f s rsultant est alors insr dans un objet ST- rcair,lir:ac1er
s r qui offre des mthodes pratiques pour accder au fichier texte.
Toute cette section d'ouverture de fichier est enchsse dans un bloc
.. r-,,',
lui-mme enchss dans une boucle v;hi1e, insre dans une nigme. Ce
bloc try est strictement rserv I'ouverture de fichier. Si une erreur se
produit pendant le processus d'ouverture, I'exception est attrape, un
message d'erreur est affich, et le programme reprend au dbut de la
boucle pour demander nouveau un nom de fichier I'utilisateur. Toutefois, si le processus aboutit un objet nouveau-n St reamReader en bonne
sant, la commande break fait sortir de la logique d'ouverture de fichier et
fait passer le chemin d'excution du programme la section de lecture.
.r\!G ./
FileRead et Fiiei^i
rite
Hdesexceptionsdefichier.VouspouVeZinsrertout|eprogrammecle
t(?,
Y
traitement de fichier dans un mme bloc t i'\,, comme dans Fi 1er'rr: j te, ou
bien vous pouvez donner son propre bloc i- r-,. la section d'ouverture de
fichier. Cette dernire solution est gnralement la plus facile, et elle
permet de gnrer un message d'erreur plus prcis.
Une fois le processus d'ouverture de fichier termin, le programme
FileRead lit une ligne de texte dans le fichier en utilisant I'appel
Chapitre 19
(et commentyremdier)
Dans ce chapitre :
'className' ne contient pas cle dfinitiol) pour'memberName'.
membre hrit'baseclassName.methodNarne'.
'subclassName' : ne peut pas hriter de la classe scelle 'baseclassName'.
'className' n'implmente pas le rrembre d'interface 'methodName'.
e faon trs scolaire, C# fait de son mieux pour trouver des erreurs
402
Il
//
]-' : ''-.:
FileRead
srrr 1e console
,,^.i*^
uarr5
Q"-+^-'
uje!rr
urrr
uy;!r,a!,
irarrg)ydL:
f rf Ei\cou
ct:-ie
rrni.i
]nai.
/c.ri.vvatl
!larrr
\Lr4l!
flLJ args)
// il
nous
faut un objet
pour
lire
1e
fichier
StreamReaoer sr;
strins
- *- -" sFiieName
= "";
// continue essayer de lire un nom de fichier jusqu' ce qu'il
// trcuve un (i.a seule manire de quitter po:r I'utilisateur esr
I I d'arrter 1e prograinne en appuyant sur Ctrl + C)
en
while (true)
{
try
{
Console. Readline
ei{ode . 0pen
FileAccess. Read)
Sixime partie
Petits supplments
par paquets de dix
400
tz
Le type d'accs: Un fichier peut tre ouvert pour la lecture, l'criture ou les deux.
llgrf
Y
fois, mon humble avis, il vaut mieux spcifier explicitement ces arguments, car ils ont un effet important sur le programme.
Dans la ligne suivante, le programme insre dans un objet StreamWriter,
sw, I'objet FileStrearn qu'il vient d'ouvrir. La classe StreamWriter permet
d'insrer les objets FlleStream, afin de fournir un ensemble de mthodes
pour traiter du texte. Le premier argument du constructeur
Stream\,n/riter est I'objet FlleStream. Le deuxime spcifie le type
d'encodage utiliser. L'encodage par dfaut est UTF8.
pas ncessaire de spcifier I'encodage pour lire un fichier.
Srream'r,n/riter inscrit le type d'encodage dans les trois premiers octets
Ou fichier. I'ouverture du fichier, ces trois octets sont lus pour dterminer I'encoclage.
,tggler^ Il n'est
5e !!\
:HW )
'J'/
1t$!Qa.
^<r7q
:(dw
\/
"n/riteLine
) et Console .\r/ri*reLine o
()
gardien de but : il est l pour attraper toute erreur de fichier qui aurait pu
se produire en un endroit quelconque du programme. Ce bloc met un
message d'erreur. contenant le nom du fichier qui en est responsable.
Mais il ne se contente pas d'indiquer simplement le nom du fichier : il
vous donne son chemin d'accs complet, en ajoutant I'aide de Ia mthode Path. Corlbirre ( ) le nom du rpertoire courant avant le nom de
Windows
sender,
1r (!IsChangeOK0)
t
e.Cancel = true;
]
5.
6.
Quoi qu'il en soit, ne vous laissez pas dcourager. Pensez la prsentation et au fonctionnement que vous attendez de votre application. Mettez
tout cela par crit. Alors seulement, vous pouvez utiliser le Concepteur
de formulaires pour dessiner les lments qui la composent. Utilisez la
fentre Proprits pour identifier les proprits, statiques et dynamiques,
que vous voulez dfinir afin que I'application fonctionne exactement
comme vous voulez.
457
398
|
I
|
/
FileAccess.Write,
fs
FileStream
FileAccess.ReadWrite
= File.0pen(sFileName,
FileMode. CreateNew,
l/
gnre un
FileAccess.lJrite) ;
avec des caractres
flux de fichier
UTFS
break;
l
I
I crit
sw.
l
I
lerne
sw. C1ose
sw
|Iriteline
le fichier
0
1ue
slnput ) ;
que nous avons cr
= null;
l
catch(IOException fe)
{
l.
ctrino
cDir = flircctnrv
GptCttrrpntDirpetorvO
string s : Path.Conbine(sDir,
Lv!J
sFileName)
\ /
:,
i
l
I
QU S-,'sten.
!i.,'sten.IO
Windows
bextChanged = true;
]
1.
fichier
RTF.
2.
3.
Slectionnez Fichier/Quitter.
La bolte de dialogue d'avertissement apparalt, comme dans Ia
Figure 18.8. Vous pouvez pousser un soupir de soulagement.
Figure 18.8 :
(i mn l oFrl'i ,: r, i^
fait apparai
- un
tre
avertissement lorsque
| 'utilisate u r
essaie de
faire quelque
Le
chose qui
provoq uera it
texle
l-JNi
aille de p
la perte de
ses dernires modifications.
J
4.
D.
655
39 6
Normalement, un programme attend qu'une requte d'l/0 sur un fichier soit satisfaite avant
de poursuivre son excution. Appelez une mthode read ( ), et vous ne rcuprerez gnralement pas le contrle aussi longtemps que les donnes du fichier ne seront pas installes
bord en scurit. C'est ce que I on appelle une l/0 synchrone.
Avec C#, les classes de System.I supportent galement les l/0 asynchrones. En les
utilisant,l'appel read ( ) restitue immdiatementle contrle pourpermettre au programme
de poursuivre son excution pendant que la requte d'l/0 est satisfaite l'arrire-plan. Le
pr0gramme est libre de vrifier ['tat d'un indicateur pour savoir si la requte d'l/0 a abouti.
C'est un peu comme de faire cuire un hamburger. Avec des l/0 synchrones vous mettez la viande
hache cuire sur la plaque chauffante, vous la surveillez jusqu' ce qu'elle soit cuite, et c'est
seulement partir de l que v0us pouvez vous mettre couper les oignons quivont aller dessus.
Avec des 1/0 asynchrones,vous p0uvez c0uperles oignons pendantque la viande hache est
en train de cuire. De temps en temps, vous jetez un c0up d'il pour voir si elle est cuite. Le
momentvenu, vous abandonnez un instantvos oignons, etvous prenez la viande sur la plaque
chauffante pour la mettre sur le pain.
Les l/0 asynchrones peuvent amliorer signif icativement les perforrnances d'un programme,
mais elles ajoutent un niveau supplmentaire de complexit.
Utlser Sj r r:eijilr\,\iriter
Les programrnes gnrent cleux sortes de sortie. Certains programrlres
crivent cles tlloc:s cle clorrnes clans un pur fornrat binaire. Ce type cle
sortie est utiie polrr stocker cles objets cl'une nranire efficace.
Beaucoup de prograrlnres. sirron la plupart. lise'nt et crivent des chanes de
texte. lisibles pilr rrn tre lturrrairr. Les classes cle flux S-,i eaiiiii:i'.er et
St-rearI'.eri,,,::r sont les 1>lus sc.ruples cles classes accueillantes pour I'homnte.
4$!Qa^ Les donnes lisibles lrar tin tre htrmain taient antrieurement cles
chalnes ASCII, (.)ri. url per-r plus tarcl, r\NSL Ces cleux siglt-'s se rfrent aux
^<v7q\
de sTandarrJisation clrri orit dfiiri t:es formats. Toutefois, le
:/dw
Y/ )
organisations
codage ANSI r)e penuet lras cl integrer les alphabets venant cle plus loin
qtre I'Ar.rtriclre l'l-st, ert cle prlrrs loin que: Harvai l'[)Lrest. Il ne peut contenir que I'alphabert l;rtin. II ne clispose pas de I'alphatret cyrilliclue, hbreu,
Windows
cet indicateur lorsqu'un fichier est lu (rien n'y a encore t rnodifi). Saisir du
texte. collper clu texte ou coller du texte dans la zone de texte assiqne - r',re
i suivante
1e programme
return true:
]
I
I
YesNo)
return dr == DialogResult.Yes;
l
IsChange0K
les
453
39 {f
,/
Une mthode dclare internal est accessible par toutes les classes
du rnme espace de nom. Aussi, I'appel c1ass2. D_internal () n'est
t/
t/
Class2 . A_public
B-protected
C_private
Class3 . D*internal"
C1ass2
C1ass1
C1ass2
E-internalprotected
Class3 . E-internaLprotected
Appuyez sur Entre pour terniner.
^1.$t
lX
K7,
Y
..
ble. Une mthode prive peut tre modifie volont sans inquiter de
I'effet que cela pourrait avoir sur d'autres classes. Une classe ou une
mthode interne de t'tathRouri nes est utilis par d'autres classes de
nature mathmatique. Si vous n'tes pas convaincu de la sagesse du
couplage faible entre les classes, allez voir le Chapitre 1 1.
4.
Figure 18.6
Donner le
,tii
n0m
FileSave
Windows
-*filffi
la proprit
.=!-..1
Click
Forml.cslDesign]*
du
sous-menu
tai!/i!::11:;
Enregistrer
gnre une
:i
Fe1ke
itit
Help
trEtul
1,,,
:,,,,,
nouvelle
fonction, qui
sera
invoque
chaque fois
que I'utilisa-
teur
slectionnera Fichier/
prrFilCiloql
,:!:l i r!
eFileC,ilrtrl
1fll
. Erp,op,,.trf-
Enreg istrer.
5.
e)
0penAndReadFile
e)
SaveSpecifiedFile 0
451
39 2
//
1a:nrne classe
C-private ( ) ;
c1ass1.C_privateO;
I I elass2,
I
I
I
I
I I class2.D*internal ( ) ;
c1ass3.D-j-nternal0;
E-internalprotected
class3 . I-internalprotected
c1ass1
return
0;
l
nrrhl i
r. voi d C nrivate 0
Console.
l
]
public void
A_pub1ic
Console. l^lriteLine
"CLass3 .A-
public" ) ;
nrntontod
vnid R nrntantpd{)
Writeline
Console.
"C1ass3
D-internal
")
l
-"h1
yuurrLi.
.r^i
vLveeus\/ ( )
!_rrrinf orna l nrntontod
vvrurl
t
Console
]
Windows
(
i.
ll
richTextBoxl.Text = "Impossible de
bReturnValue = true:
]
return bReturnvalue:
l
AP\
=qt
Un diteur qui lit tout le fichier en nrmoire est beaucoup plus facile
crire qu'un diteur qui err laisse la rnajeure partie sur le disque. En tout
cas, C# ne limite pas son cornposant i :lr-,-extB,rx au tampon n-rmoire si
frustrant de 64 Ko du Bloc-notes.
SinpleEditcr en le
//
ll
//
succs
if (saveFileDialogl
ShowDialog
) == DialogResult,0K)
System,I0.Stream strOutput
= saveFileDialogl.0penFile0
449
390
nanespace Paint
t
int
nBLue)
{l
l
rrqil
y4L
v^+.".D..-.i;.ss
-^tr l-1o
Lrrl\!] Lf L
T
L
o nom
dnns
args)
ll
aiorto
Peint-
:':x
sn2n(
r1
'l
esfi1r
s on cherche
^,,+^^^+.i ^,,^*^
/I /I auromarrquenent
,,^.i-^
uDrrr6 D.;-+.
r arll L ,
black. Paint 0
car
PaintColor. StaticPaint ( ) ;
j
J
Tous les progrilnrf nes (:onlnlencellt par la cotumande i.,sing S.r'sieiri;, Elle
dr>nne aLr proqrilnln)l rrn accs alltomatique toutes les fonctions cle la
bibliothque systr'rnre, contlne irrrtei,: rE i r.
Windows
Figure 18.5
Dposer sur
iiil,..:
E,r:ils FeDh{-
BelF
(i'rnloF.li+;r
-un c0mp0sant
'lp.-rFiieJialcg
.=j:-:J.*tti&
fornrl.cs IDesign]+
. { tr:nrr:
Lfrt,osirrts
et un
comp0sant
E,lilrn
Frml
Sa-re-Filei!:loq
a
pp0re
l'essentiel du
dialogue
ncessaire
I'ouverture et
l enregistrement de
fichiers.
1l
I
Fotns
I "t'innonos
I lf;l t-onte; ll'lenr:
i:rJ TnelEat
|
5tatusEar
I
1,,.,
t^hlil'trlcon
E
5
oFBnFiletl'rE
q
-j[J
,-.,
-FntL,r'3lah]
SiveFiletrl,1
E rrlrro,rt4
PfE:s-F6Erers circulir
iper,FitrDr.:1r,11 B:xr./E:rlDttrql
Gin:rl
$ eoli* : ruiils i@
3.
Assignez la proprit
les fichiers | *.*".
Filter
Cette opration indique 0penFileDialog de ne rechercher initialement que les fichiers RTF, mais laisse I'utilisateur la possibilit
de rechercher tous les fichiers.
4.
Filr,pr du composant
447
388
Transiariorilibrai,;
vite le problme : f i
Tra i'rs iat- ic l.ili b r a l'.-
class MyClass {}
class UrClass ll
l
1,.,
il , :.i,. s t
MySt'.rff.
^1'$q
]X
IrT9,
Y
un espace de nom portant le mme nom que le rpertoire qu'il cre. Examinez tous les programmes cle ce livre: ils ont tous ts crs I'aicle cle
I'Assistant Application. Par exemple, le programme Ai ignOrir:pl1t a t cr
dans le dossier,t lipnr-)ir'f.1r,: t. Le nom du fichier source est (llassl . cs, qui
correspond au nom de la classe par dfaut. Le nom de I'espace de nom dans
lequel se trouve C,lassl. cs est le mme que celui du dossier:Aligro'.rrp1,1t.
Si vous ne spcifiez pas ur-re dsignation d'espace de nom, C# place
votre
classe dans I'espace de nom global. C'est I'espace de nom de base pour
tous les autres espaces de nom.
class Sort
{
public void
SomeFunction
Windows
'. J
ll s'il y a quelque
l'
trackBarl.Maximun)
SetFont
l
l
catch I i ;
df\
=)
445
386
ne peut pas tre modifi par deux programmeurs en mme temps. Chacun
d'eux a besoin de son propre fichier source. Enfin, la compilation d'un
module de grande taille peut prendre beaucoup de temps (on peut toujours
aller prendre un caf, mais il arrive un moment o votre patron devient
souponneux). Recompiler un tel module parce qu'une seule ligne d'une
seule classe a t modifie devient intolrable.
.cs
t/
Un fichier source ne peut tre modifi que par une seule personne la
fois. Vous pouvez avoir vingt trente programmeurs travaillant en
mme temps sur un grand projet. Un seul fichier pour vingtquatre
programmeurs impliquerait que chacun d'eux ne pourrait travailler
qu'une heure par jour, supposer qu'ils se relaient vingtquatre heures
sur vingtquatre. Sivous divisiez le programme en vingtquatre fichiers,
il serait possible, bien que difficile, que tous les programmeurs travaillent en mme temps. Mais si vous divisez le programme de telle
manire que chaque classe a son propre fichier, I'orchestration du
travail de ces vingtquatre programmeurs devient beaucoup plus facile.
t/
La rgnration complte d'un grand programme comme un systme de rservation de billets d'avion peut prendre beaucoup de
temps. Vous n'aurez certainement pas envie de rgnrer toutes les
instructions qui composent le systme simplement parce qu'un
programmeur a modifi une seule ligne. Avec un programme divis
en plusieurs fichiers, Visual Studio peut rgnrer uniquement le
fichier modifi, et rassembler ensuite tous les fichiers objet.
Windows
l.
,
r oI
l.
3.
invoque quand
e)
I Ia convertit en chane et la
I \a TextBox pour accorder les
copie dans
deux
4.
5.
6.
de police.
La Figure 18.4 montre le rsultat. Il est vrai qu'une simple image n'est pas trs
parlante, mais la valeur qui appart dans la zone de texte Taille de police est
instantanment mise jour selon la position de I'index dans la barre, pendant
que le texte slectionn est agrandi ou rduit en consquence.
443
38 4
a s
0)
JetOnS Un COup
questions d'hritage, mais le principe est le mme. Par exemple, une mthode
4.
Windows
e)
isBolded = !isBolded;
nenultemi0.thecked - i.sBolded;
SetFont
e)
isltalies = !isltalics;
isltalics
nenultenli.Checked =
SetFont ( )
ll
et
t- -,t
5.
public
Forml
()
//
Required
for
lT.lirL^rr,
(
"cornponent
441
382
le
l/
Inverse
retourne 1/x
if (nValue0f0bject :=
0)
0", this)
l
)
return 1.0
(double)nValueOf0bject;
l
l
public class
Class1
try
I
//
prend
inverse de
catch(Exception e)
{
e.ToStrins0);
1
J
//
..")
l
]
Windows
Editiffi
Figure 18.2
Fofmt
;t - . 1l a
p tp.z+- a
',rn.
lt4(g
,le W: rd
v!
'
texte
venant de
Word a
conserv sa
Le
mise en
forme.
.9tlfl
-=(fl,
Tala de
poke
[---
8*24
Changer de police et de
taille
Changer de police, mettre le texte en gras ou en italique est en fait presque la mme fonction. Vous pouvez donc vous pargner quelques efforts
en crant une seule fonction capable de raliser ces trois oprations,
comme ceci
ll----
FontStyle
if
t
fs *
(isBolded)
FontStyle.Regular;
439
38 0
Renvoyer le mme objet exception prsente un avantage et un inconvnient. Cela permet aux fonctions intermdiaires d'attraper des exceptions
pour librer ou fermer des lments allous par elles, tout en permettant
I'utilisateur final de I'objet exception de suivre I'indication de pile
jusqu' la source de I'exception. Toutefois, une fonction intermdiaire ne
peut pas (ou ne doit pas) ajouter des informations supplmentaires
I'exception en la modifiant avant de la renvoyer.
eption conventionnel
/i
I
MyException
private
MyClasss myobject;
base(sMsg)
myobject =
mo;
l/
public
MyClass MyObject{
get {return
nryobject;
))
//
II
II
CustomException
- cre
//
et voil,
nous avons ce
return (string)
qu'il
Windows
nous faut
o;
l.
2.
l ( ) et
ReadClipboard ( ).
Utilisez pour cela dition/Couper, dition/Copier, et dition/Coller.
3.
4.
5.
I'option de menu de telle sorte que c'est cette mthode qui est
invoque lorsque I'utilisateur clique sur celui-ci.
6.
7.
e)
437
37 8
types d'exception dfinie pour la brillante bibliothque cle classe que je viens
d'crire (c'est pour a que je I'appelle tsr-iI lrantLi i r a:'.). Les foncticns qui
composent Bri i I iant -rhraii- envoient et attrapent des exceptions
llyExc ept ion.
#i
(l-,
vous ne savez pas quoi faire avec une exception, laissez-la passer pour
qu'elle arrive la fonction appelante. Mais soyez honnte avec vous-mme :
ne laissez pas passer une exception parce que vous n'avez simplernent pas
le courage d'crire le code de traiternent (l'erreur correspondant.
Si
Relancer un obiet
Dans certains cas. une mthode ne peut pas traiter entirement une
erreur, mais ne veut pas laisser passer l'exception sans y mettre son grain
de sel. C'est comme une fonction mathn-ratique clui appelle jr':r,r'',,r-.,.. i ()
pour s'apercevoir qu'elle renvoie une exception. Mme si la cause premire du problme peut tre une donne incorrecte. la fonction mathmatique est peut-tre en mesure de fournir des indications supplmentaires sur ce qui s'est pass.
Un bloc catch peut digrer partiellement I'exception envoye et ignorer le
reste. Ce n'est pas ce qu'il y a de plus beau, mais a existe.
L'interception d'une exception d'erreur est une chose trs courante pour
les mthodes qui allouent des lments. Par exemple, imaginez une
mthode F O qui ouvre un fichier quand elle est invoque, et le referme
quand elle se termine. Quelque part dans le cours cle son excution, F' )
invoque G O . Une exception envoye de G ( I passerait directement
travers F O sans lui laisser la moindre chance de fermer le fichier. Celui-ci
resterait donc ouvert jusqu' ce que le programme lui-mme se termine.
Une solution idale serait que F O contienne un bloc catch qui ferme les
fichiers ouverts. Bien entendu, r (l est libre de passer I'exception au
niveau suprieur aprs en avoir fait ce qu'il fallait pour ce qui la concerne.
Il y a deux manires de renvoyer une erreur. La premire ccinsiste
envoyer une deuxime exception, avec les mmes informations ou ventuellement des informations supplmentaires
:
6ena
!bDrr tgnnier
QdilJ
Windows
Fetbe
*"'i;.#..iilt'.':,;
F[hPr edtion
f-l
L:)
::
Formt
o,
[l -;/
r L:--l
..
....
a.
::iirb
el,-irr!
.ii5rb EllsmE
i,frit
.,,
E:
.r1,}inl
8:r lr:if
I
r
rrd,:I
'n:t'
lEenr
Figure 18.1
Ia,lle de
p(Jrcdq
E Lrrr
F
r,r,::rre,i
Ibleu 5trinq[
tliT:Lfl
!i rllf:i,::
Tii
m0deste
-c0mposant
TextBox
o-a-.
Mme le
....
des dizaines
de proprits
a ctives.
.t
r}
r{rl
7
11 )
l
l
que I'utilisateur peut y copier un objet, par exemple du texte, dans une
application, et le coller dans une autre.
La mthode SetDataOb j ect de la classe Clipboard (le clipbocrd est le
Presse-papiers) crit un objet Data0b ject dans le Presse-papiers. L'objet
DataOb ject contient les donnes stocker et la description de leur type.
dPi
-Q)
L'identification du type de donne est trs importante. Par exemple, I'utilisateur peut essayer de couper le contenu d'une feuille de calcul et de le coller
dans la fentre de Si inpl e-ECitor. S'il n'y avait pas un moyen de filtrer ce
contenu, SimpleEditor afficherait une chne de n'importe quoi (au mieux).
435
37 6
lJriteline
Console.
(e. Message)
I tZ - -
uurrL
f^,,hli^
,,^;
{
L!.I
IJ ( bIxceptlonlype/
\
;
l
catch (MyException
me)
l^Iriteline
(ne. Message)
l
]
I I tl - - n'essayez pas d'attraper des exceptions
public void f3 (boo1 bExceptionType)
{
f4 (bBxceptionType)
ll t4'-
if
(bExc eptionType
f40");
new C1ass1
0 . f1 (fa1se)
de mes exceptions
Ghapitre 18
Lier ensemble deux contrles pour que les modifications effectues dans I'un
soient refltes dans I'autre.
..R,:r^
uRttqFg
;ar
i-l#
,
37tl
'I
catch(Exception
e)
t
I
ici
l
Si ScmeOtherFunct-t on ( ) envoyait un objet Ex-cepr:ion, celui-ci ne serait
pas attrap par I'instruction catch (l'lyException) car une Exception
n'est pas de type l1','E:icepti;n. Il serait attrap par I'instruction catch
.)
ll
objet
=(t
9D'\
pec
l"fr;-
i a lExc e pt io n envoy.
gnrale
nlln
I 1n
lrn1d
\m81lhn11n
grrl !:vrr
I I
\ /
+ rlr
LI
Y
Some0therFunction
l
catch (Exception
me)
It
I tols
ici
1
J
catch (MyException e)
,-
//
II
aucune exception ne
l
Dans cet exemple, I'instruction catch la plus gnrale coupe I'herbe sous
le pied de la suivante en interceptant tous les envois.
Les proprits que vous n'avez pas modifies sont les proprits par
dfaut de I'objet, qui n'apparaissent donc pas dans le code, Par exemple,
vous pouvez voir que trackBarl est ancre sur AnchorSryles. Bottom,
AnchorSty Les. Lef t et AnchorStyles. Right. D'autre part, les proprits
llaxirnum et Minimum reoivent les valeurs 24 et 8, et la proprit Val ue, la
taille de police initiale, reoit la valeur 12.
Enfin, dans tous les exemples que vous pourrez trouver, explorez la mthode
InitializeCornpcnenrs 0 jusqu' ce que vous arriviez comprendre ce qu'a
fait le Concepteur de formulaires. Ce procd vous permettra de dcouwir
de nouveaux composants et leurs proprits, et vous donnera une ide de ce
quoi ils servent.
Et maintenant
43 I
37 2
Cette classe Crsr-omExcepticn st faite sur mesure pour signaler une erreur
au logiciel qui traite avec la tristement clbre I'i',.C i: ss. Cette sous-classe
d'Exc -aption met de ct la mme chalne que I'original, mais dispose en
plus de la possibilit de stocker dans I'exception la rfrence au fautif.
public class
C1ass1
public void
SomeFunction0
try
t
exemple
SoneOtherFunction0;
I
autres oprations.
l
catch (MyException
me)
string s = me.ToString0;
MyClass no
mthodes
= ne.MyCustonObject;
MyClass de
s'afficher
1ui-mrie
l
l
public void
SomeOtherFunction0
I I eration de nyobject
l'lyClass myobject = new MyClass 0 ;
signale une erreur concernant myobject
II
throw new l'lyException("Erreur dans 1'objet de MyC1ass", myobject);
I
I .
reste de 1a fonction
429
'n
Figure 11.12:
Une fois
convenablement ancrs,
les composants de
-i
mnl oFrJit,rr
en suivent
fidlement le
Taille de p,:fice
redimensionnement.
l--
Qu'atlons-nous fabriqu
///
///
l//
(summary)
Sunrnary
(lsunnary)
public class I'orrnl
System,l,Jindows.Forms,Form
t
this.mainMenul = new System.Windows.Forns.MainMenu0
this.menulteml = nev System.Windovs.Forns.Menulten0
this.trackBarl = nev System.ldindovs.Forns,Track3ar0
/l
;
;
;
II
/
il
naintlenul
this.mainMenul.MenuTtems,AddRange(new
System.Windows,Forns.l'lenuTtem[] {
this,menuItenl.
37 0
l,'lai:' ir est le point cle clpart clr-r programme, il est bon cle toujours
1t!BIQa^ Comme
en placer le contenu dans un bloc i i:-,-. Toute exception qui ne sera pas
"attrape" ailleurs remontera finalernent jusclu' i'1a j n r. ) . C'est donc votre
)
\/
dernire opportunit cle rcuprer une erreur avant qu'elle aboutisse
Windows, dont le message d'erreur sera beaucoup plus difficile ir-rterprter.
avz-; \
:(dq9
E>:,:r1,'r.
ic
et utilise sa
mthode'laS'-rlr. 'r porlr afficher sous frlrme d'une sirnple chane la rnajeure
partie des informations sur I'erreur contenues dans I'objet exc epi i ,.r.
,.t\v-_
,a
tLapropritExce.:i.ltiil:.i].::.-::]i:E]retclurneunSouS-ensenrblepluslisible.
J-^t
:
llcf
Y
i = 6, factorielle = 720
i = 5, factorielle : 120
i - 4, factorielle = 24
i = 3, factorielle = 6
i = 2, factorielle *
i = 1, factorielle =
i = 0, factorielle = 0
2
1
Erreur fatale
Appuyez
line
52
reur
fa-
_ Ghapitre
Figure 17.9
Laisser aux
17 :
mmes
-endroits les
composants
lorsque le
formulaire est
Iarlle
redimensionn
n'est sans
doute pas ce
'ie
p.rlice
l-_-
qu'attendent
les utilisate u rs.
et gauche du formulaire.
2.
3.
redimensionnait le formulaire).
4.
5.
r:i,,.r
427
368
La fonction SomeFunction O contient un bloc de code identifi par le motcl try. Toute fonction appele dans ce bloc, ou toute fonction qui I'appelle, est consiclre comme faisant partie du bloc tr';'.
Un bloc tr',r est immdiatement suivi par le mot-cl catch, lequel est suivi
par un bloc auquel le contrle est pass si une erreur se produit en un
endroit quelconque dans le bloc try. L'argument pass au bloc catch est
un obiet de Ia classe E;<ception ou d'une sous-classe de celle-ci.
un endroit quelconque dans les profondeurs cle SomeOtherFunction O,
une erreur se produit. Toujours prte, la fonction signale une erreur
I'excution en envoyant (thror.) un objet Exception au premier bloc pour
f"-fJ
f--t'I.y.)
I |",1
CI
//
ll
II
FactorialException
factorielle qui
indique Factorial
en
usrrr8
',^:^-
utilisant
1es arguments
lllicites
un objet Exception
(.,a+^a.
y s Lerii;
nanespace FactorialException
t
//
II
l,tyltatnfunctions
-.,L1.:
^ -1^^^
yuurrL
"rooo MyMthFunctions
ll
It
Tactorial
nValue)
ngatifs
string s = String.Format(
'rArgument
ngatif
illicite
3.
^dK
=qg,
4.
Figure 17.8
SimpleEditor
est prt pour
aller danser.
Taille de
po[ce
l-*
425
366
d'erreur que Ia fonction appelante ne teste pas. Bien str, en tant que programmeur en chef, je peux me laisser aller profrer des menaces. Je me souviens
d'avoir Iu toutes sortes de liwes de programmation regorgeant de menaces de
bannissement du syndicat des programmeurs pour ceux qui ne s'occupent pas
des codes d'erreur, mais tout bon programmeur FORTRAN sait bien c1u'un
langage ne peut obliger personne vrifier quoi que ce soit, et que, trs
souvent, ces vrifications ne sont pas faites.
Souvent, mme si je vrifie I'indication d'erreur retourne par Fa': t ,, r -a L i i
ou par toute autre fonction, la fonction appelante ne peut rien faire d'autre
que de signaler I'erreur. Le problme est que la fonction appelante est
oblige de tester toutes les erreurs possibles retournes par toutes les
fonctions qu'elle appelle. Bien vite, le code commence avoir cette allure l:
1a
traite
return
MY_ERROR_1;
if (errRtn == SF-ERROR2)
{
return
l
I
My_ERROR-2;
appelle SomeOtherFunctions,
errRtn = someOtherFunc0
if (errRtn == SOF ERROR1)
1it 1'erreur,
Console.l'trriteline("Erreur de type
return
MY_ERR0R*3;
if
(errRtn == SOF-ERROR2)
return
MY-ERROR-/*;
l
Ce mcanisme prsente plusieurs inconvnients
t/
t/
Ghapitre 17
3.
=!'I-fiSHffi
::
:)';: i'.
: ., , jt :
i ?:t?l l-,-
,' :
Hdp
t et!'l
text0oxl
Figure 17.7
Certaines
proprits,
c0mme
Font, sont
,-l
{n
5vstem.!Vrndws,Forms
Bn.kr:lo1 f Wrndow
Sorders[yle F]red3D
aursor
l8eam
E Font
llrcrosorl 5n5
ForCr,lor I wrndowTe, t
El Lines
lableau String[
RrghiToleft
5crollBf'
en fait un
No
lJone
ftfltextao*t
TexlA|gn
Left
B i.urt2rv|ur.t't
AcceFtsPtlrr, Fal.e
Ac.eFtsTb
False
llt,Dro
Fils
ensemble de
SOUS-
proprits,
que vous
devez dfinir
Text
Le lexl conteru dn! ce cmtr6l,
individuellement.
4.
423
364
if (dFactorial =:
l'lyMathFunctions.NON-INTEGER-VALUE)
Console
}lriteLine
a.f.iche 1e
rsultat
chaque pssge
i, MyMathFunctions.Factorial(i)
..
Console.ReadO
"Appuyez
de tests. Le
parce qu'il
(0
accept
est
premier regarde si la valer-rr passe est ngative
une
immdiatement
retourne
fonction
donne un rsultat raisonnable). Si oui, la
sa
version
compare
est
I'argument
indication d'erreur. Si non, la valeur de
entire : si elles sont gales, c'est que la partie dcimale de I'argument est nulle.
U
=)
Dans la convention sur les noms Southern Naming Convention, les noms des
constantes sont entirement en majuscules, les mots tant spars par un tiret
de soulignement. Certains programmeurs, plus libraux, refusent de faire
allgeance, mais ce n'est pas la convention qui a des chances de changer.
t'
::::'' " .,
Figure 17.6:
La proprit
Shortcut
-permet de
spcifier le
raccourci
clavier que
vous v0ulez
assigner
| lment de
menu.
7.
8.
Vous pouvez taper dans la zone de texte et ouvrir les diffrents menus
principaux. Naturellement, au point o nous en sommes, simpleEditor
est encore plus que simple. C'est une coquille vide. Si vous slectionnez
Fichier/Quitter, il ne se passe rien du tout. II vous faut ajouter du code
derrire chacun de ces lments de menu pour qu'ils fassent quelque
chose. C'est le sujet du Chapitre 18.
42 I
362
{cg)
Le programme
Fac
tori
a1E
rr
r Re
ncessaires :
I
I
II
I
actatialErrorReturn
using
System;
nanespace FactorialErrorReturn
{
//
II
MyMathFunctions
.:rl'
u' e
ffi
Heb
'as*':
'i'
q \
Boitewtils
Donres
aompNt5
Flrm
. T-"t
Windows
...
..
. . ....
..
*l'splitlr
fi oomsnupcbwn
ll? Numsrl-FDm
F lfskBa
Figure 17.4:
La zone
t,-Progr5igd
RlchTextBox
-est I endroit
Qf nthrextaox
''ttj rfr4d.st
o l'utilisaeur p0urra
l Helpprovider
3r rootp
El contextf'lenu
:j loobr
Prtr-ppias ccrrire
diter son
texte dans
![Prslua
6en
Lv!.
4.
l.
ici.
4l I
360
dis bien jamois.' si vous n'avez pas I'intention de dboguer vos programmes et si vous ne vous souciez pas qu'ils marchent, alors seulement c'est
peut-tre une bonne ide.
Le programnle !-ar:tur i alErrcr suivant mclntre ce qui arrive quand les
erreurs ne sont pas cltectes. Ce programme calcule et affiche la fonction
factorielle pour de nombreuses valeurs, dont certaines sont tout juste licites.
1. Par
La factorielle du nonrbre N est gale N " (N-l) . (N-2)
exemple, la factorielle de 4 est 4 * 3 * 2 * 1, soit 24. La fonction factorielle
n'est valide que pour les nombres entiers naturels (positifs).
ll
II
II
using
crer et
Factoriall.{ithError
utiliser
une fonction
System;
namespace
Factoriall,IithError
li
/
MyMathFunctions
public class
MyMathFunctions
I
t
//
II
Factorial
dValue
do
{
dFactorlal *= dValue;
dValue -= 1.0;
J while(dValue ) 1);
// retourne 1a valeur stocke dans
1'accumulateur
return dFactorial;
J
chaque
fois
C'est dans la mthode InitializeComponent que sont crs les composants Windows. Le commentaire spcial plac iuste avant cette fonction
dit en effet : "Ne touchez pas cette section du code, parce que c'est l
que moi, le Concepteur de formulaires, je fais mon boulot." En fait, le
Concepteur gnre le code situ entre les commentaires lf t
et
"gton
/endregion, rponse ce que je dessine.
Dans ce cas simple, I'application commence par dfinir le membre
AutoScaleBaseSize de I'objet this. Je suis pas trs str de ce qu'est cette
proprit. Heureusement, comme c'est le Concepteur de formulaires qui
s'en occupe pour moi, je n'ai pas besoin de le savoir, mais je sais que thls
est I'objet Form lui-mme. En continuant jusqu' la dernire ligne de
Initiali zeComponent, je peux voir que "Simple Editor" est assign
this. Text.
Prenez le temps d'tudier soigneusement ce point, car c'est l I'essentiel
du Concepteur de formulaires. Le Concepteur affiche les proprits du
formulaire. L'une de ces proprits est Text, laquelle j'ai donn la valeur
"Simple Editor". Le Concepteur a ajout une ligne de code qui assigne en
consquence cette valeur la proprit Text du formulaire.
La mthode lispose est invoque lorsque Forml est ferm. Elle n'est pas
particulirement intressante dans ce cas, parce que la fermeture du
formulaire ferme aussi l'diteur.
l.
U
^tK
'qE,)
Le terme composonf ne s'applique pas seulement aux objets graphiques, mais tous les objets graphiques sont des composants. C'est
donc ce terme que nous utilisons ici.
4 |7
Heureusement pour tous ceux qui sont concerns, C# a cart les problmes de pointeur en se dbarrassant des pointeurs en gnral. Les rfrences qu'il utilise la place sont indpendantes du type et ne peuvent pas
tre manipules par I'utilisateur pour en faire quelque chose qui pourrait
dmolir le programme.
nublic class
Student
47 5
fichiers "include", qui sont alors utiliss par les modules ; toutefois, il
peut devenir trs compliqu de placer tous ces fichiers include dans le
bon ordre pour que votre module se compile correctement.
C# se dbarrasse de cette absurdit en recherchant lui-mme les dfinitions de
classe, et en les trouvant. Si vous invoquez une classe StuCen*., C# recherche
et trouve lui-mme la dfinition de cette classe pour s'assurer que vous I'utilisez correctement. Il n'a pas besoin pour cela que vous lui donniez un indice.
Account
balance
0.0;
numChecksProcessed
checkBook
0;
= new CheckBook0;
l
]
Account
orivate
1
numChecksProcessed
CheckBook checkBook
= 0;
new CheckBook0;
47 7
Les programmeurs ont ensuite ralis que I'interface, plus lgre, pouvait
rendre les mmes services. Une classe qui implmente une interface,
comme I'exemple suivant, promet C# comme tout le monde qu'elle
offre les mthodes read ( ) et r,rrite ( ) correspondantes :
interface IPersistable
{
void
read O
void writeO;
i
/i
int i *
5;
affiche un
Non seulement je peux invoquer la mme mthode sur un lnt que sur un
objet de M1'Cias s, mais je peux aussi le faire avec une constante comme
"5". Ce scandaleux mlange des types de variable est une fonctionnalit
puissante de C#.
479
Index
NET
description 3, 5, 7
A-UN 280
quand utiliser 281
Abstract 318
Abstractlnheritance 3 I 8
Abstractlnterface 343
Abstraction 231, 232
Accs
des membres de
classe, restreindre 239
contrle de l', 237 244, 246
AccessControl 391
Accesseur 250
Addition sur des chalnes.
oprateur 202
Aide
en cours d'dition 196
plus
195
AlignOutput 218
Ancrer un contrle dans un
formulaire 426
Application
ajouter des actions l8
commentaires 26
console
cadre de travail 26
crer 24
crer un modle de 22
dessiner 12
ajouter
des actions 433
des contr6les 422
des tiquettes 424
concevoir la
prsentation 4l 1
connaltre les
composants 431
construire les menus 419
crer le cadre de
travail 413
dfinir 410
dessiner 412
redimensionner le
formulaire 426
Argument(s)
accorder dfinition et
utilisation
partir d'une
fentre 168
un programme 164
fonction
154
plusieurs une
fonction
145
surcharger une
fonction
147
Arithmtique (oprateurs) 53
Array (classe) 116
syntaxe I 17
Arrondir
37
Assembleur 4
Assignation, oprateur de 56
Assistant Applications 8
Asynchrone (l/O) 396
Automatique, saisie 190
AverageAndDisplay 145
AverageAndDisplayOverloaded 148
AverageStudentGPA 125
AverageWith
CompilerError
146
146
par dfaut,
implmenter
149
passer
I'invite de DOS 165
MainQ 164
partir de Visual
documentation
196
BankAccount 240,291
BankAccountC ontructors-
AndFunction 266
lndex
String 201
Classif ication 234, 235,
273,311
Clipboard 435
Commandes de boucle 79
Comment aire 26
de documentation 195
balise 196
Comparaison, oprateurs
de 59
Continue 85
Contrle
ancrer dans un formulaire 426
d'accs 237,244,246
dans une application
I'invite de 165
Dossier de classement d'une
22
Double 39
DoubleBankAccount 246
15
Conversion
CompareQ 204
avec majuscules et
minuscules 208
Comparer des nombres 41
Compteur 44, 45, 47,52
utiliser une variable
comme 41
Concatnation 47,221
Concepteur de formulaires 12
implicite 464
invalide, viter en
utilisant is 284
Conversion de temprature 40
Convert 212
Couplage 391
CustomException 380
252
comment se fait la
construction
262
de la classe de base,
passer des arguments
au 288
de structure 348
et hritage 286
invoquer 286
surcharger 263
ConstructorSavingsAccount 291
quitter 452
codes d'erreur 365
application, crer un
modle de22
classe 173
Const 116
Constante numricue
dclarer 50
Console,
type 50
Constructeur(s)
classe 136
DOS, passer des arguments
application
proprits
d'exceptions 367
Espace de nom
accder des modules
du rnme 388
contrler I'accs aux
classes avec 391
Decimal 42
limitations
44
vitesse de calcul 44
DecimalBankAccou nt 247
Dclaration
tableau 123
Dclarer
constante numrique 50
variable 32
DemonstrateDefault-
Constructor 256
Dessiner une application
12
Destructeur 293
Dterministe 294
DisplayArguments 164
DisplayRoundedDecimal 149
DisplayXWithNestedloops 95
Distribu (dveloppement) 5
Do... while 84
Documentation
commentaire de 195
balise 196
XML, gnrer 200
dclarer 388
runir des fichiers
source dans 387
utiliser avec using 390
EST-UN 278
exemple 368
intercepter et
renvoyer 378
laisser passer 375
utiliser un mcanisme
cle 367
Excutable 4
483
Index
instructions if imbriques 76
Incrmentation, oprateurs
de 57, 58
Logique
oprateurs 61
type bool 44
de comparaison 59
InheritingAConstructor 286
Initialisation, rfrence non
initialise 112
Instance 106,234
Int 33, 35
Interface
crer soi-mme 332
abstraite 342
description 329
et hritage342
exemple 330
prdfinie 334
InvokeBaseConstructor 289
InvokeMethod 179
Is 284, 308
IsAllDigits 213
Italique (mettre en) 439
7-K
Java 5
redfinir
accidentellement 302
ou ajouter un test 301
rles
MainQ, passer des
arguments 164
Majuscules 208
Masquer Toir redfinir
Membre
de classe, restreindre
I'accs 239
donne 136
d'un objet, accder 107
fonction
136
d'une application
Windows, construire 419
implmenter les
options 440
Mthode 181
abstraite 318
accs 394
dclare
comme virtuelle 309
machine 4
Late binding 306
Length 122
Liaison
prcoce 306
tardive 306
Lire les caractres saisis au
clavier 210
complet
d'une mthode 182
d'une fonction 296
conventions sur 48
de classe 105
de fichier ,lire 446
de fonction,
Langage(s)
d'assemblage 4
de haut niveau 4
Java 5
Nachos 231
New 258, 469
Nom
Menus
Label425
c#3,5
181
Minuscules 208
MixingFunctionsAndMethods 188, 196
Modle 8
ModifyString 203
147
internal 394
private 393
protected 393
public 393
dfinir 179
diffrente selon la
classe 297
redfinir
surcharger
de variable 127
298
espace de 387
Nombre(s)
comparer des 41
en virgule flottante,
comparer 60
entr au clavier 215
format de sortie
224
rels 38
Notation hongroise 49
Null
111
rfrence 161
Numrique
entre, analyser 212
485
lndex
Replace 221
utiliser 396
String 46,202
classe 201
convertir en un autre
type 212
StringReader 395
StringToCharAccess
StringWriter
TextReader 395
2I0
395
Struct 346
Structure 346
constructeur de 348
Saisie automatique 190
sur les fonctions de la
bibliothque
standard 191
sur vos propres fonctions et mthodes 193
SavingsAccount 279
Sceller une classe 325
Sealed 325
Scurit
niveaux de 243
SetX 250
Signe (variable) 37
SimpleEditor 410
enregistrer avant de
et classe 345
exemple 350
mthodes d'une 349
types structure
prdfinis 353
StructureExample 350
Surcharger Voir aussr
redfinir
constructeur 263
fonction I47,296
une mthode
d'une classe de base 298
hrite 296
Switch 97
pour tester une chane 209
quitter 452
fentre d'dition 417
SimpleSavingsAccou nt 27 5
T
t
Sortlnterface 336
SortStudents 130
Source 4
fichiers
diviser un programme
en plusieurs 385
split
fixe I 17
variable 120
dclaration 123
dpassement de taille 119
251
StreamWriter 395
124
foreach 127
index
215, 223
Statique
membre d'une classe 115
proprit
d'objets
118
longueur 123
proprit Length 122
trier
Test 162
TextBox 422
changer la taille de
police en utilisant 444
128
TextWriter 395
This 184
absent 188
explicite
Throw 367
185
Tolnt32 212
Tolnt64 212
ToString 384
TrackBar 424
changer la taille de
Try 367
Type
assigner un 65
bool 44
char 45
const
116
conversion de 45
conversion de, le cast 51
conversion explicite,
le cast 65
conversion implicite 64
de longueur fixe 49
de rfrence, oprateurs
sur
111
decimal 42
decimal, int, et float
(comparaison) 44
dclar, utiliser chaque
fois 306
dfini par le programmeur 50
d'expression, accorder 63
double 39
d'une constante 50
d'une opration,
calculer 63
487
erlt?ll .sr^E-I
raurudur.p 9^r{JV
488
entiers divers 35
tendue 42
valuation par 107
float 38
fonction avec ou sans 160
int
33
intrinsque 49
string 46
convertir
212
et char, comparais on 47
struct 346
structure prdfinie
353
type valeur 49
unifier le systme de 353
vitesse de calcul selon
le 42
TypeUnification 354
en virgule
flottante 38
flottante, comparer 60
flottante, dclarer 38
flottante, limitations 40
flottante, prcision 39
initialiser 467
logique 44
nom 127
non dclare 462
passer par rfrence
une fonction 154
ou par valeur
151
rgles de
dclaration 34
porte 90
signe oLr non signe 37
.structure 346
utiliser comte
cornpteur 41
VariableArrayAverage 1 20
VehicleDataOnly 109
Virgule flottante 38
comparer des nombres
en 60
format
cle
Pentium
calcul du
41
limitations 40
prcision 39
Virtuelle, mthode, dclarer
Valeur, valuation par, 107
Variable
de longueur fixe 49
decimal, dclarer 43
dclarer 32
comme 309
Visual Basic 20
Visual Studio
fentres de 13
interface utilisateur 13
plus d'aide 195
saisie automatique 190
Void
16i)
While 80
Windttws
crer une application
avec C#
dfinir une
application 410
gnrer et excuter un
premier programme 11
Presse-papiers 435
WriteBinary
Writeline
395
173
X-Z
XML 196
documentation,
gnrer 200
Zro, rfrence 161
486
excutable 4
excuter en dposant un
fichier dessus
Obiect (classe) 285
Objet(s)
accder
, mthodes pour 245
aux membres d'un 107
changer de classe 282
constructeur 252
courant 181
177
programmation
oriente 231
110
de
stocker en mmoire
PassByReferenceError I 54
PassByValue 151
PassObject 176
PassObiectToMember177
Pentium
calculs en virgule
flottante
41
vitesse de calcul 42
PEUT_TRE-UTILISCOMME 327
Police, changer de 439
107
string 202
structure 346
Prcision 39,41
Presse-papiers 435
Programmation
fonctionnelle 233, 235
tableau de I24
Oprateur(s)
d'addition sur les
d'incrmentation 57.
d'objet
115
Length 122
statique 251,434
Protection, niveau de 466
Public 105,239
exemple 240
g Etl
58
logiques 6l
ordre d'excution 55
111
simples 54
231
langages de 3
Readline
Redfinir
accidentellement 302
une mthode d'une
abstraction
chanes 202
ternaire 66
Oriente objet
(programmation)
Out 153, 158
Polymorphisme 305,306
accder une mthode
redfinie 308
Porte des variables, rgles
Proprit(s)
active 177,434
de 90
115
point
2I5
Polymorphiclnheritance 309
proprit(s)
ParseSequenceWithSplit
PassByReference 153
Function
accder 183
courant, this 184
distinguer les uns des
autres I I I
d'une classe abstraite 320
fonctions et mthodes
de, dfinir
null 111
Pad 217
168
interface 236
modle de 8
passer des arguments
164
231
c#
238
application
contrler manuellement
Ia sortie 217
dfinir une application
Windows 410
dfinition 4
diviser en plusieurs
fichiers source 385
212
48 4
G# pour
les Nuts
Excuter un programme en
dposant un fichier
dessus 168
conditions mutuellement
exclusives,
contrler,
Expression
accorder les types 63
valuation 55
70
exemple, 71
foreach, 127
goto, 100
switch,
Concepteur de
formulaires
97
Fonction
appele mthode 181
d'accs 250
dfinir et utiliser 135
FactorialErrorRetur n 362
FactorialException 368
FactorialWithError 360
Factorielle 360
Factoring 311
Fahrenheit 40
False 44
partir d'une
Proprits
168
15
Rsultats 11
Fermeture (bouton de),
implmenter 456
Fichier(s)
Iire le nom du 446
rassembler des donnes
dans 394
RTF 418
crire 449
lire
448
source 4
diviser un programme
en plusieurs 385
FileWrite 397
Final 367
FixedArrayAverage 118
Float 38
FIux d'excution
12
redimensionner 426
Four micro-ondes 231
Fraction
prcision 39
reprsenter 37
FunctionsWithDefaultArguments 149
membre
d'une classe 136
statique d'une classe,
Fentre
Code 18
de Visual Studio 11
passer des arguments
ajouter un contrle
dans 14
74
dfinir
177
11
une application l7
GetX 250
nom 147,207
complet 296
passer
des arguments 143
des arguments d'un
type valeur
Gnrer
Goto 100
Gras (mettre en) 439
151
rfrence 152,154
des arguments par
valeur
151
un objet 175
pourquoi ? I42
qui ne retourne pas de
valeur, dfinir 160
retourner une valeur 157
sans type 160
surcharger 147,296
type ou non type 160
utiliser return 157
void ou non-void 160
Writeline
Formulaire
12
utilit 274
HidingWithdrawal 299
Hirarchie de classes 321
Hongroise (notation) 49
HTML 196
173
For 91
Foreach 127,210
Format 224
RTF 418
Hritage 272
et constructeur 286
et interfac e 342
exemple 275
I,
I/O asynchrones 396
If, 70
viter le else
75
482
G#
BankAccountContructorsAndThis 267
BankAccountWithMultipleConstructors 263
Base 288, 303
Bote outils 13
Bool 44
conversion 45
Bord, effets de252
Boucle(s)
break et continue 85
briser 85
commandes de 79
do... while
for 91
84
quoi sert-elle ? 92
exemple 91
imbriques 93
while 80
Boxing 159
Caractre
d'une 210
Compare 204
concatnation 47,221
contrler manuellement
la sortie d'un
programme 217
convertir en un autre
Iype 212
Break 85
de contrle 224
description 3, 5,
CalculatelnterestTablewithFunctions 138
CalculatelnterestWithEmbeddedTest 76
110
d'exceptions
crer 371
redfinir
380
et structure 345
tendre 323
factoring 3l I
faiblement couple 391
fonction membre 136
statique d'une,
dfinir
177
fortement couple
391
invariabilit 204
lire 210
oprateur
historique
*47
crer une application
Windows avec 7
hritage 272
hirarchie de
crer une nouvelle 324
redmarrer 321
Format 224
C#
classification 273, 31 I
Console 173
contenant d'autres
classes 1 13
d'addition
108
instance 234
d'une 106
202
Parl217
membre(s)
Replace 221
Char 45
donne 136
statiques d'une 115
ne pouvant tre
instancie que
localement 270
nom, majuscules et
minuscules 105
Classl
object
Split 215,223
suite de chiffres taps au
clavier, traiter 215
Trim2IT
utiliser srvitch avec
209
164
285
Classe 104
abstraite
utiliser 318
Array I 16
scelle 470
sceller 325
objet
105
282
membres 239
sous-class e 234
47I
C# n'y va pas par quatre chemins. Il dit qu'un int fait 32 bits et qu'un long
fait 64 bits, et que c'est comme a. En tant que programmeur, vous pouvez envoyer cela votre banque ou un autre ordinateur sans qu'il en
47 6
this.
sName
sName)
sName;
public string
get
IL
rtrrrn
St-jno
nOpy(SName)
nom
;
class {yClass
t
cirrdonf cot/<lr{g1t.get0
've\/
+ " Kringle");
L'LbL'
1
J
System;
public class
Student
i
n+g.r'ar
pr].vare
^-.i,'^+^
srrlng
public string
-t\T^*^.
sr\ame;
Nane
set{sNane=value;}
get { return String.Copy(sName); l
l
l
class
MvClass
student.Nane = student.Nane
"Kringle"
]
]
47 4
tz
t/
Un objet de pile est propre une fonction (ce qui est une bonne
chose), mais son allocation disparat lorsque la fonction retourne
son rsultat. Tout pointeur qui pointe vers un objet dont I'allocation
mmoire a t supprime devient invalide. Ce serait trs bien si
quelqu'un avait prvenu le pointeur, mais le malheureux s'imagine
toujours qu'il pointe vers un objet valide, et le programmeur aussi.
tz
Le problme est qu'il est trop facile d'oublier quel type de mmoire se
rfre un pointeur. Un objet du tas doit tre retourn quand on en a fini avec
lui. Oubliez-le, et votre programme aura de moins en moins de mmoire
disponible, jusqu' ce qu'il ne puisse plus fonctionner. D'un autre ct, si
vous librez plus d'une fois le mme bloc du tas pour "retourner" un bloc de
la mmoire globale ou de Ia pile, votre programme est parti pour une longue
sieste. Il faudra peuttre Ctrl+Alt+Del pour le rveiller.
47 2
public class
I'lyClass
n)
public string
ConvertPositiveNurnbers
(int
n)
I I oy positive
if(n)0)
t
string s
tLulll
numbers
n.ToString0;
de I'application.
3 attendue
Ce message indique que C# attendait encore une accolade fermante Ia
fin du listing. Quelque part dans le code, vous avez oubli de fermer une
dfinition de classe, une fonction ou un bloc if . Reprenez votre code et
appariez soigneusement les accolades ouvrantes et fermantes jusqu' ce
que vous trouviez la coupable.
.9\..4
I(/ll
\p1/
-
47 0
new
l
i
t/
Vous vouliez vraiment hriter de la classe de base par polymorphisme, auquel cas vous auriez dt dclarer les deux classes de la
faon suivante
public class
BaseClass
l
]
BaseClass
public
overrides void Function0
-l
L
l
]
alllllfa
rlr,,/t \ Colr
o-/nhd{ \ ""'* n'g5t
=\d\y /
\/
paS Une
468
n=
1.
l.
2.
3.
mettant fin
I'excution du programme, il est possible qu'il y ait quelque chose qui
466
MyClass
float
return fResult:
l
Cette version de la fonction utilise une constante 2.0 de type f 1o.r au lieu
du type dor-Lbie par dfaut. Un f ioat multipli par un f loat st ur r i,,-.r.
elle n'a pas accs. Par exemple, une mthode d'une classe peut essayer
d'accder un membre priv d'une autre classe (voyez le Chapitre l1) :
public class
MyClass
public void
SomeFunction0
que MyClass
I
)
public class
YourClass
private int
nPrivateMember
0;
En gnral, I'erreur n'est pas aussi flagrante. Bien souvent, vous avez simplement laiss le descripteur hors de I'objet membre ou de Ia classe elle-rnme.
464
en
"/'
naa
= lfl
MyClass
^ -"11'r
^
^r^r'r
Ld.LJ.
PUUrr(:
float
FloatTimes2
(float
On pourrait croire que multiplier par deux un type f loat ne pose pas de
problme, mais c'est justement l qu'est le problme. 2.0 n'est pas de type
f loat mais de type double. Un f loat multipli par un double donne un
double. C# ne va pas stocker une valeur de type double dans une variable
de type f 1oat, cause - vous avez devin - de la perte d'informations qui
pourrait en rsulter (dans ce cas, plusieurs chiffres de prcision).
Les conversions implicites peuvent dconcerter plus encore le lecteur
dsinvolte (c'est mon cas, dans les bons jours). Cette version de
Floa*.-Times2 ( ) marche trs bien
class
MyClass
46 2
parfois affreusement bavard. J'ai rcluit certains des messages d'erreur pour
les faire tenir sur une page. En plus, il y a dans un message d'erreur diffrents
endroits o apparat le nom d'un membre donne offensant ou d'une classe
irrvrencieuse. J'ai remplac ces noms par variableflane, memberName ou
c
las sNane.
for(index = 0; index
{
( 10; index++)
instructions
La variable index n'est dfinie nulle part (pour savoir comment dclarer
for(int
t
index =
0; index ( 1t;
index++)
instructions
Chapitre 6).
Il y a en fait plus de chances que vous ayez fait une faute de frappe dans
un nom de variable. En voici un bon exemple :
class Student
i
oublic
strine sStudentName;
r.--------..o
public int nID;
l
^1^^^
r D M.,a1^^^
|rJ/ vrd
u
Dans cette
partil...
1t
V
Les nuls
456
l.
fentre du programme.
2.
3.
4.
45 4
void !Filpnpn|,nh'ipnt
44vvrv-.
conrlor
(rrci-om Frrontl
-, _.^,,\rgs e)
return:
l
/
OpenAndReadFile
// \a
LT^--+nL^--^)
urcLUlld.lLu = false;
1'tat
non modifi
e)
de modificati.on
bTextChanged
= false;
l
]
e)
//
ll
if
return;
]
I
Application.Exit 0
Dans tous les cas, la mthode J s rlhang-e0K r. ) s51 invoque avant d'excuter
une opration qui pourrait provoquer la perte d'une modification.
Il nous manque encore quelque chose : il faut que I'indicateur bTextthar,e ert
reoive la valeur r rLre chaque modification apporte dans la zone de texte.
Ir.icl'rTe;iiii.,.x nous donne ce qu'il nous faut : la proprit dynamique
Tertchange,j i,i, qui est invoque chaque fois que quelque chose modifie le
452
Figure 18.7
SlnpleEdit rr
est maintenant un
r--l t:it+
,t t+ ,-:.r++
,,la|,-, rliffr?frt+:, i,lr _ 1,.:
diverses tailles
divers styles
vrita ble
diteur,
capable de
lire d'un seul
coup de gros
fichier
Taille de police
[E*
RTF
l.
2.
3.
pileExir i. j
que
e)
Application.Exit0;
]
450
if
(str0utput !=
nu11)
bReturnValue = true:
l
]
return bReturnValue;
l
Cette fonction suit exactement le mme chemin que la mthode
OpenAndReadFlle O que nous avons vue plus haut. Pour commencer, elle
ouvre la bolte de dialogu SaveFileDiaiog, et attend qu'elle lui retourne
OK. Le programme essaie alors d'ouvrir le fichier. Si I'opration aboutit, le
programme crit dans le fichier tout le contenu de la proprit Rtf de la
zone de texte R.ichTexttsox.
Nous avons ajout le composant Sa-,'eFiieDialog SirnpleEditor: en le
faisant glisser depuis la Bolte outils. Aucun ajustement n'a t ncessaire.
Pour implmenter les options de menu Fichier/Ouvrir et Fichier/Enregistrer, suivez ces tapes :
iedFile
l.
()
menu Fichier/Enregistrer.
3.
448
ll |it
dans 1a RichTextBox
bool bReturnValue
false:
try
{
owre le fichier
System,I0.Stream
if (strlnput
!=
strlnput
openFileDialogl.0penFile0
nu11)
I si I'ouverture du fichier
// un lecteur de flux
System. I0.StreamReader
strRdr
(strlnput)
I 7it tout
string
1e contenu du fichier
sContents = strRdr.ReadoEnd0
puissent 1e lire
strRdr. Close O ;
l
l
]
catch (Exception e)
446
4.
5.
6.
SiinpleEditor ne serait
l.
dj MainMenul).
2.
444
Figure 18.4:
Grce au lien
tabli entre
-CES dEUX
ri: i'elr,ri,:,lerriann"
composants,
la valeur qui
apparat dans
la
,* ;"i
::r:rer
CgftineS paftieS
$ fA nd iS
l'irrdi{,lu
lr,t,:,1.:
er, t'-,,',rnt
E,;r
lextBrx
est mise
jour en
fonction de
la
position de
l'index dans la
lE
TrackBar.
Changer de
l.
2.
3.
TextBox
I t:-t
1e contenu de 1a TextBox
e)
442
il
^--- uOflstructor
^
rvuv. nuu
tr// mnnn.
^lt arry
//
COde
la police 1e style et
donne
tiet.E-ont t I
+a1 | lo
nr
.lf ,Ut
6.
7.
8.
quelconque.
La Figure 18.3 montre du texte mis en gras et en italique dans la fentre de
-qirnpleEdrtor" Remarquez aussi que les options actives I'endroit o se
trouve le curseur sont prcdes d'une coche dans le menu, qui vous permet
donc de savoir guelle sera la mise en forme du texte que vous allez taper
partir de l. C'est le rsultat de notre dfinition de la proprit Checked.
Wi":
Firhier dilim
-lal-xl
FBrmt
Figure 18.3:
SinpleEditor
permet
maintenant
de saisir du
texte en gras
Taille de
et en
ita liq
policr
l--
e.
composants diffrents.
Changer de
440
if
fr l:
FontStyle.Bold;
{isTtalics)
La base de cette fonction est le constructeur Font ( ). Il en existe de nombreuses versions, mais celle-ci admet les arguments qui nous intressent
cre donc un nouvel objet Font, avec la mme police mais dans une nouvelle
taille, et dont les attributs gras et italiques ont ventuellement t changs.
.j99q
SZ' .-\
,-
v-/
,,
L'expression richTextBoxl . Font f ont; modifie la police de tout le
texte qui se trouve dans la zone de texte.
lnplmenter
Click, et
3.
438
e)
j.teC1 ipboard
rtfText)
e)
string s = ReadClipboardO;
if (r
l= null)
richTextBoxl. SelectedRtf = s;
l
]
Double-cliquer sur le nom d'une proprit dans la fentre Proprits vous conduit directement la fonction correspondante. Cette
astuce peut faire gagner pas mal de temps.
8.
9.
10.
I
l.
436
ii
rcupre
le
contenu du Presse-papiers
Tn-+^nL.i^^+
I
= Clipboard.GetDataObject0
r,eLqvvJ.",
ut
if
(data == nu11)
return nul1;
]
rcupres,
vrifie qu'el1es
if
sruv/
(o == nul1)
return
nu11;
return nul1;
l
rurvv/
t;
sont
43 4
La fentre Proprits contient aussi un ensemble de proprits compltement diffrent, qui correspondent plutt aux mthodes de C#. Je les
^tK
'(dg,
Les proprits dynamiques sont plus communment appeles des vnements. La mthode qui est invoque lorsque l'vnement se produit
s'appelle un gesfionnoire d'unemenl. Mais je ne veux pas introduire de
complications inutiles.
Les proprits actives d'un objet sont les mthodes invoques par C#
lorsque certaines circonstances particulires se produisent. Par exemple,
la proprit Button. Click est invoque lorsque que I'utilisateur clique
sur un bouton. Mais ces proprits actives offrent un contrle bien plus
prcis que cela. Par exemple, si vous voulez diffrencier le fait d'enfoncer
un bouton ou de le relcher, vous avez une proprit diffrente pour
chacune de ces deux actions. Une proprit active est dclenche quand
le pointeur se trouve sur un bouton, que I'utilisateur clique ou non, et
c'est une autre proprit qui passe I'action lorsque la souris va ailleurs
(c'est gnralement ce qui est utilis pour changer la couleur d'un bouton
quand le pointeur passe dessus).
Pour accder aux proprits actives, slectionnez le composant, et cliquez sur
le bouton contenant un clair en haut de la fentre Proprits. La Figure 18.1
montre une partie des proprits actives d'un composant TextBox.
Afin que le programme SinipleEditor fasse ce que I'on attend de lui, vous
devez dfinir une ou plusieurs proprits actives pour chacun de ses
composants. SimpleEdi tor paralt soudain moins simple.
430
this . nenutem5
this . nenultemg
this . nenulteml2 ] ) ;
,
,
ll
II
trackBa
Ittl
( (System. Windows,
Left
Forns.AnchorStyles.lottom
h'
System,I,lindorrs.Forns.AnchorStyles.Right) ;
this.trackBarl.Location = ner+ System.Drar+ing.Point(40, 248)
^
this.trackBarl.MaximrLn = 24;
this . trackBari .Minimum = 8;
this.trackBarl.Nane = "trackBarL" ;
this.trackBarl.Size = new Systern.Drauing.Size(208,
this . trackBarl . TabIn dex = 2;
this . trackBarl . Value = 12 ;
42) ;
l
/lendregion
]
I
J'ai supprim toutes les sections qui ne concernent pas le menu principal
(MainMenu), I'une des options du Menu, et la TrackBar. Chacun de ces
objets est un membre donne de la classe Form1. Le Concepteur de
formulaires cre les noms de ces membres donne en concatnant le type
de I'obiet avec un numro.
pu vous faire dfinir des noms dans la fentre Proprits pour
^s$c ^.. J'aurais
quelque
obtenir
chose de plus parlant, mais c'tait sans importance. Pour
7X
programmes
de grancle taille, la dfinition de vos propres noms peut
des
ttg||
V
rendre le code qui en rsulte beaucoup plus facile lire.
La mthode
Initial.i
zoe nmnnnt I
chaque type.
.*a/
ft?ll
\SZt
llE!l
428
Ancrage
RichTextBox
Bas
Bas
Tra ckBa r
Bas, gauche
Bas, droite
Figure 17.10:
Cliquez sur les
bras de la
fentre
d ancrage
p0ur
slectionner
(gris fonc) ou
dslectionner
(blancl
I
ancrage
dans chaque
direction.
Figure 17.11
Le oetit
SinpleEdit,:r.
Taille de
police
[-
426
Redinensonner le fornulaire
Les utilisateurs aiment que les fentres soient redimensionnables. Pour
tre plus prcis, les utilisateurs peuvent avoir envie de redimensionner le
formulaire de SimpleEditor. Par dfaut, un formulaire est
redimensionnable, mais les objets qu'il contient ne le sont gnralement
pas. C'est une chose laquelle vous pouvez remdier, mais la solution n'est
pas triviale.
Si vous voulez faire simple, ne permettez pas aux
utilisateurs de
l.
P\
g/
e,
424
Slectionnez la zone de texte, et cliquez sur I'outil Centrer horizontalement dans la barre d'outils Disposition.
La zone de texte est centre horizontalement dans le formulaire.
6.
Venons"en maintenant notre TrackBar. Slectionnez le composant TrackBar dans la Bote outils, et placez-Ie tout en bas du
formulaire
imp 1 eEci
it o r.
422
Raccourci
Fichier/0uvrir
Ctrl0
Fichier/Enregistrer CtrlS
Fichier/0uitter
Ctrl0
dition/Couper
CtrlX
Copier
CtrlC
ditioni
dition/Coller
Format/G
ras
CtrlV
CtrlB
Format/ltalique
Ctrll
?F1
Ajouter
SimpleEditor doit aussi tre capable de modifier la police, dans certaines limites arbitraires. Dans cette section, vous allez ajouter une zone de
texte dans laquelle I'utilisateur pourra taper la taille qu'il veut donner la
police. SirnpleEditor disposera aussi d'un contrle analogue, que I'on
.ffi
SimpleEditor plus facile utiliser, cette fonctionnalit permet aussi de montrer comment relier deux contrles.
En dehors de rendre
l.
420
2.
commencer.
/,
lirhier Edihon
Affihqe
iffi
' Forml,ci [Derig"]"
tr-
eLei1
'
Uelp
'-$."1'l
.-s
|'
bite
^l
-.l
out'l.j
oonnees
connosent
Figure 17.5
Le composa nt
I
I
Potnte'rt
t"t'"t
I A
I A tir*taua
I J. *uon
t=lstr rex(uor
ll(1a111lqL1U
VOUS
propose de
taper I option
du menu
:J
I
i di
l'4nMeru
r".t**..
l'
Rdio&tton
6roupBo.
43 PEtureBo!
i.-l tun"t
principal et
celle du
oatecrid
Fres-ppier5
qtrcul
Gnrl
s0us-menu.
Wind6$rs Forft,s
*eoil"u*t,tr[d-T
3.
4.
D.
6.
4|8
3.
Au vu de ce symbole,
si
b'
-'ii
21,90
llungryMinds-
First
(143,6s
F)
Lfr
Cette icne signale une
(n
FU
retenir ceci.
nJ
2
www.efirst.com
f-\
65 3303 B
tsBN-2-84427-2s9
"'i
n
,,j
p-(
J
,llilIxilrililill[|iltlll
tJ
Finst