Les propriétés du langage C# sont très proches de celle
du langage Delphi, mais elles sont plus complètes et restent cohérentes
avec la notion de membre en C#.
1.1 Définition et déclaration de propriété
Définition d'une propriété
Une propriété
définie dans une classe permet d'accéder à certaines
informations contenues dans les objets instanciés à partir
de cette classe. Une propriété a la même syntaxe de
définition et d'utilisation que celle d'un champ d'objet (elle possède
un type de déclaration), mais en fait elle invoque une ou deux méthodes
internes pour fonctionner. Les méthodes internes sont déclarées
à l'intérieur d'un bloc de définition de la propriété.
|
Déclaration d'une propriété propr1
de type int :
public int propr1 {
//...... bloc de définition
}
|
Un champ n'est qu'un emplacement de stockage dont le contenu peut être
consulté (lecture du contenu du champ) et modifié
(écriture dans le champ), tandis qu'une propriété
associe des actions spécifiques à la lecture ou à
l'écriture ainsi que la modification des données que la
propriété représente.
1.2 Accesseurs de propriété
En C#, une propriété fait systématiquement appel à
une ou à deux méthodes internes dont les noms sont les mêmes
pour toutes les propriétés afin de fonctionner soit en lecture,
soit en écriture. On appelle ces méthodes internes
des accesseurs; leur noms sont get
et set , ci-dessous un exemple
de lecture et d'écriture d'une propriété au moyen d'affectations
:
Accesseur de lecture
de la propriété :
Syntaxe :
get { return ..... ;}
cet accesseur indique que la propriété est en lecture et doit
renvoyer un résultat dont le type doit être le même que
celui de la propriété. La propriété propr1 ci-dessous est déclarée en lecture
seule et renvoie le contenu d'un champ de même type qu'elle :
private int champ;
public int propr1{
get { return
champ ; }
}
|
Accesseur d'écriture
dans la propriété :
Syntaxe :
set { ....}
cet accesseur indique que la propriété est en écriture
et sert à initialiser ou à modifier la propriété.
La propriété propr1 ci-dessous est déclarée
en écriture seule et stocke une donnée de même type qu'elle
dans la variable champ :
private int champ;
public int propr1{
set { champ = value ;
}
}
Le mot clef value est une sorte de paramètre implicite
interne à l'accesseur set, il contient la valeur effective
qui est transmise à la propriété lors de l'accès
en écriture.
|
D'un manière générale lorsqu'une propriété
fonctionne à travers un attribut (du même type que la propriété),
l'attribut contient la donnée brute à laquelle la propriété
permet d'accéder.
Ci-dessous une déclaration d'une propriété en lecture
et écriture avec attribut de stockage :
private
int champ;
public int propr1{
get {
return champ ; }
set
{ champ = value ; }
} |
Le mécanisme de fonctionnement est figuré ci-après
:
Dans l'exemple précédent,
la propriété accéde directement sans modification à
la donnée brute stockée dans le champ, mais il est tout à
fait possible à une propriété d'accéder à
cette donnée en en modifiant sa valeur avant stockage ou après
récupération de sa valeur.
1.3 Détail et exemple de fonctionnement
d'une propriété
L'exemple ci-dessous reprend la propriété propr1 en lecture et écriture du paragraphe
précédent et montre comment elle peut modifier la valeur brute
de la donnée stockée dans l'attribut " int champ " :
private
int champ;
public int propr1{
get {return champ*10;}
set {champ = value + 5 ;}
} |
Utilisons cette propriété en mode écriture à
travers une affectation :
Le mécanisme d'écriture est simulé ci-dessous :
La valeur 14 est passée comme paramètre dans la méthode
set à la variable implicite value, le calcul value+5
est effectué et le résultat 19 est stocké dans l'attribut
champ.
Utilisons maintenant notre propriété en mode lecture à
travers une affectation :
Le mécanisme de lecture est simulé ci-dessous :
La valeur brute 19 stockée dans l'attribut champ est récupérée
par la propriété qui l'utilise dans la méthode accesseur
get en la multipliant par 10, c'est cette valeur modifiée de 190 qui
renvoyée par la propriété.
Exemple pratique d'utilisation
d'une propriété
Une propriété servant à fournir automatiquement
le prix d'un article en y intégrant la TVA au taux de 19.6% et arrondi
à l'unité d'euro supérieur :
private
Double prixTotal ;
private Double tauxTVA = 1.196
;
public Double prix {
get {
return Math.Round(prixTotal);
}
set {
prixTotal = value * tauxTVA ;
}
}
|
Ci-dessous le programme console C#Builder exécutable :
using System ;
namespace ProjPropIndex
{
class Class {
static private Double prixTotal
;
static private Double tauxTVA
= 1.196
;
static public Double prix
{
get
{
return Math.Round (
prixTotal
) ;
}
set
{
prixTotal =
value
* tauxTVA
;
}
}
[STAThread]
static void
Main
( string
[] args ) {
Double val =
100 ;
System .Console.WriteLine
("Valeur entrée :"
+ val );
prix =
val
;
System .Console.WriteLine
("Valeur stockée :"
+ prixTotal
);
val
= prix ;
System .Console.WriteLine
("valeur arrondie (lue) : "
+ val
) ;
System .Console.ReadLine
( );
}
}
}
|
Résultats d'exécution :
Explications des actions exécutées
:
On rentre 100€ dans la variable prix :
Double val = 100 ;
prix =
val
;
Action effectuée :
On écrit 100 dans la propriété prix et
celle-ci stocke 100*1.196=119.6 dans le champ prixTotal.
On exécute l'instruction :
val = prix ;
Action effectuée :
On lit la propriété qui arrondi le champ prixTotal
à l'euro supérieur soit : 120€
1.4 Les propriétés sont
de classes ou d'instances
Les propriétés,
comme les champs peuvent être des propriétés
de classes et donc qualifiées par les mots clefs comme
static, abstract etc ...Dans l'exemple précédent
nous avons qualifié tous les champs et la propriété
prix en static afin qu'ils puissent être accessibles à
la méthode Main qui est elle-même obligatoirement static.
|
Voici
le même exemple utilisant une version avec des propriétés
et des champs d'instances et non de classe (non static) :
using System ;
namespace ProjPropIndex
{
class clA {
private Double prixTotal ;
private Double tauxTVA =
1.196 ;
public Double prix {
get
{ return Math.Round
( prixTotal
) ; }
set
{ prixTotal
= value
* tauxTVA
; }
}
}
class Class {
[STAThread]
static void
Main
( string
[] args ) {
clA Obj
= new
clA
( );
Double val =
100 ;
System .Console.WriteLine
("Valeur entrée :"
+ val );
Obj.prix =
val ;
// le champ
prixTotal n'est pas accessible car il est privé
val
= Obj.prix
;
System .Console.WriteLine
("valeur arrondie (lue) : "
+ val
) ;
System
.Console.ReadLine ( );
}
}
}
|
Résultats d'exécution :
1.5 Les propriétés peuvent être
masquées comme les méthodes
Une propriété sans spécificateur particulier de
type de liaison est considérée comme une entité
à liaison statique par défaut.
Dans l'exemple ci-après nous dérivons une nouvelle classe
de la classe clA nommée clB, nous redéclarons dans la classe
fille une nouvelle propriété ayant le même nom, à
l'instar d'un champ ou d'une méthode C# considère que nous
masquons la propriété mère et nous suggère le
conseil suivant :
[C# Avertissement] Class...... : Le mot clé
new est requis sur '...........', car il masque le membre hérité......
'
Nous mettons donc le mot clef new devant la nouvelle déclaration
de la propriété dans la classe fille. En reprenant l'exemple
précédent supposons que dans la classe fille clB, la TVA soit
à 5%, nous redéclarons dans clB une propriété
prix qui va masquer celle de la mère :
using System ;
namespace ProjPropIndex
{
class clA {
private Double prixTotal ;
private Double tauxTVA = 1.196 ;
public Double prix { // propriété
de la classe mère
get
{ return Math.Round
( prixTotal ) ;
}
set
{ prixTotal
= value
* tauxTVA
; }
}
}
class
clB
: clA
{
private Double prixLocal ;
public new Double prix
{ // masquage de la propriété de la classe mère
get { return Math.Round (
prixLocal
) ; }
set
{ prixLocal
= value
* 1.05
; }
}
}
class Class {
[STAThread]
static void
Main
( string
[] args ) {
clA Obj
= new
clA
( );
Double val =
100 ;
System .Console.WriteLine
("Valeur entrée clA Obj :"
+ val );
Obj.prix =
val
;
val =
Obj.prix
;
System .Console.WriteLine
("valeur arrondie (lue)clA Obj : "
+ val
) ;
System .Console.WriteLine
("--------------------------------------");
clB Obj2 =
new clB
( );
val =
100
;
System .Console.WriteLine
("Valeur entrée clB Obj2 :"
+ val );
Obj2.prix =
val
;
val =
Obj2.prix
;
System .Console.WriteLine
("valeur arrondie (lue)clB Obj2: "
+ val
) ;
System .Console.ReadLine
( );
}
}
}
|
Résultats d'exécution :
1.6 Les propriétés peuvent être
virtuelles et redéfinies comme les méthodes
Les propriété en C# ont l'avantage important d'être utilisables
dans le contexte de liaison dynamique d'une manière strictement identique
à celle des méthodes en C# , ce qui confère au langage
une "orthogonalité" solide relativement à la notion de polymorphisme.
Une propriété
peut donc être déclarée virtuelle dans une classe de
base et être surchargée dynamiquement dans les classes descendantes
de cette classe de base.
|
Dans l'exemple ci-après semblable au précédent, nous
déclarons dans la classe mère clA la propriété
prix comme virtual, puis :
- Nous dérivons clB, une classe fille de la classe clA possédant
une propriété prix masquant statiquement
la propriété virtuelle de la classe clA, dans cette
classe clB la TVA appliquée à la variable
prix est à 5% (nous mettons donc
le mot clef new devant la nouvelle déclaration de la propriété
prix dans la classe fille clB).
La propriété prix est dans cette
classe clB à liaison statique.
- Nous dérivons une nouvelle classe de la classe clA
nommée clB2 dans laquelle nous redéfinissons en
override la propriété prix ayant le même nom, dans cette classe clB2
la TVA appliquée à la variable prix est aussi à 5%. La propriété
prix est dans cette classe clB2
à liaison dynamique.
Notre objectif est de comparer les résultats d'exécution obtenus
lorsque l'on utilise une référence d'objet de classe mère
instanciée soit en objet de classe clB ou clB2. C'est
le comportement de la propriété prix
dans chacun de deux cas (statique ou dynamique) qui nous intéresse
:
using System ;
namespace ProjPropIndex
{
class clA {
private Double prixTotal ;
private Double tauxTVA = 1.196 ;
public virtual Double prix
{ // propriété
virtuelle de la classe mère
get
{ return Math.Round
( prixTotal ) ;
}
set
{ prixTotal
= value
* tauxTVA
; }
}
}
class clB
: clA
{
private Double prixLocal ;
public new Double prix
{ // masquage de la propriété de la classe mère
get { return Math.Round (
prixLocal
) ; }
set
{ prixLocal
= value
* 1.05
; }
}
}
class
clB2
: clA
{
private Double prixLocal ;
public override Double prix
{// redéfinition de la propriété
de
la classe
mère
get {
return Math.Round (
prixLocal
) ; }
set
{ prixLocal
= value
* 1.05
; }
}
}
class Class {
static private Double prixTotal
;
static private Double tauxTVA
= 1.196
;
static public Double prix
{
get
{ return Math.Round
( prixTotal
) ; }
set
{ prixTotal
= value
* tauxTVA
; }
}
[STAThread]
static void
Main
( string
[] args ) {
clA Obj
= new
clA
( );
Double val =
100 ;
System.Console.WriteLine
("Valeur entrée Obj=new clA :"
+ val );
Obj.prix =
val
;
val =
Obj.prix
;
System.Console.WriteLine
("valeur arrondie (lue)Obj=new clA : "
+ val
) ;
System.Console.WriteLine
("----------------------------------------");
Obj =
new
clB ( );
val =
100
;
System.Console.WriteLine
("Valeur entrée Obj=new clB :"
+ val );
Obj.prix =
val
;
val =
Obj.prix
;
System.Console.WriteLine
("valeur arrondie (lue)Obj=new clB : "
+ val
) ;
System.Console.WriteLine
("----------------------------------------");
Obj =
new
clB2 ( );
val =
100
;
System.Console.WriteLine
("Valeur entrée Obj=new clB2 :"
+ val );
Obj.prix =
val
;
val =
Obj.prix
;
System.Console.WriteLine
("valeur arrondie (lue)Obj=new clB2 : "
+ val
) ;
System.Console.ReadLine
( );
}
}
}
|
Résultats d'exécution :
Nous voyons bien que le même objet Obj instancié en classe
clB ou en classe clB2 ne fournit pas les mêmes résultats
pour la propriété prix, ces résulats sont conformes
à la notion de polymorphisme en particulier pour l'instanciation en
clB2.
Rappelons
que le masquage statique doit être utilisé comme pour
les méthodes à bon escient, plus spécifiquement lorsque
nous ne souhaitons pas utiliser le polymorphisme, dans le cas contraire c'est
la liaison dynamique qui doit être utilisée pour définir
et redéfinir des propriétés.
|
1.7 Les propriétés peuvent être
abstraites comme les méthodes
Les propriétés en C# peuvent être déclarées
abstract, dans ce cas comme les méthodes elles sont automatiquement
virtuelles sans necéssiter l'utilisation du mot clef virtual.
Comme une méthode abstraite, une propriété abstraite
n'a pas de corps de définition pour le ou les accesseurs qui la composent,
ces accesseurs sont implémentés dans une classe fille.
Toute classe déclarant une propriété abstract
doit elle-même être déclarée abstract,
l'implémentation de la propriété a lieu dans une classe
fille, soit en masquant la propriété de la classe mère
(grâce à une déclaration à liaison statique avec
le mot clef new), soit en la redéfinissant (grâce
à une déclaration à liaison dynamique avec le mot clef
override) :
abstract
class clA {
public abstract
Double prix
{ // propriété
abstraite virtuelle de la classe mère
get ; // propriété abstraite en lecture
set ; // propriété abstraite
en écriture
}
}
class clB1
: clA
{
private
Double prixTotal
;
private Double tauxTVA = 1.196 ;
public new Double prix
{ // implantation par masquage de la propriété
de
la classe
mère
get { return Math.Round (
prixLocal
) ; }
set
{ prixTotal
= value
* tauxTVA
;
}
}
}
class
clB2
: clA
{
private
Double prixTotal
;
private Double tauxTVA = 1.05 ;
public override Double prix
{ // implantation par redéfinition de la propriété
de
la classe
mère
get { return Math.Round (
prixLocal
) ; }
set
{ prixTotal
= value
* tauxTVA
;
}
}
}
|
1.8 Les propriétés peuvent être
déclarées dans une interface
Les propriétés en C# peuvent être déclarées
dans une interface comme les événements et les méthodes
sans le mot clef abstract, dans ce cas comme dans le cas de propriété
abstraites la déclaration ne contient pas de corps de définition
pour le ou les accesseurs qui la composent, ces accesseurs sont implémentés
dans une classe fille qui implémente elle-même l'interface.
Les propriétés déclarées dans une interface
lorsqu'elles sont implémentées dans une classe peuvent être
définies soit à liaison statique, soit à liaison dynamique.
Ci dessous une exemple de hiérarchie abstraite de véhicules,
avec une interface IVehicule contenant un événement (
cet exemple est spécifié au chapitre 2.4 sur les interfaces
) :
abstract class
Vehicule { // classe abstraite mère
....
}
|
interface
IVehicule {
....
string TypeEngin
{ // déclaration
de propriété abstraite par défaut
get ;
set
;
}
....
}
|
abstract class
UnVehicule : Vehicule , IVehicule {
private string nom
= "";
....
public virtual
string
TypeEngin { // implantation virtuelle
de la propriété
get
{
return nom ;
}
set { nom = "["+value+"]" ; }
}
....
}
|
abstract class Terrestre
: UnVehicule {
private string
nomTerre =
"";
....
public override string
TypeEngin {
// redéfinition de propriété
get {
return base .TypeEngin
; }
set
{ string
nomTerre =
value
+ "-Terrestre";
base
.TypeEngin
= nomTerre ;
}
}
}
|
1.9 Exemple complet exécutable
Code C# complet compilable avec l'événement
et une classe concrète
public delegate void Starting ( );
// delegate declaration de type pour l'événement
abstract class
Vehicule { // classe abstraite mère
public abstract void Demarrer ( ); // méthode abstraite
public void
RépartirPassagers
( ) { } // implantation de méthode
avec corps vide
public void
PériodicitéMaintenance
( ) { } // implantation de méthode
avec corps vide
}
interface IVehicule {
event Starting OnStart ;
// déclaration d'événement
du type délégué : Starting
string TypeEngin
{ // déclaration
de propriété abstraite par défaut
get ;
set
;
}
void Stopper ( ); // déclaration de méthode abstraite par défaut
}
//-- classe abstraite héritant
de la classe mère et implémentant
l'interface :
abstract class UnVehicule :
Vehicule , IVehicule {
private string nom
= "";
private string [ ] ArrayInfos
= new
string
[10] ;
public event Starting OnStart
;
protected void LancerEvent ( ) {
if( OnStart
!= null)
OnStart ( );
}
public virtual
string
TypeEngin { // implantation virtuelle
de la propriété
get
{
return nom ;
}
set { nom = "["+value+"]" ; }
}
public virtual void Stopper ( ) { } // implantation virtuelle
de méthode avec corps vide
}
abstract class
Terrestre
: UnVehicule {
private string
nomTerre =
"";
public new void RépartirPassagers
( ) { }
public new void PériodicitéMaintenance
( ) { }
public override string
TypeEngin {
// redéfinition de propriété
get {
return base.TypeEngin ; }
set
{ string
nomTerre =
value
+ "-Terrestre";
base.TypeEngin =
nomTerre
; }
}
}
class Voiture :
Terrestre {
public override
string
TypeEngin {
// redéfinition de propriété
get { return base.TypeEngin + "-voiture";
}
set
{ base.TypeEngin = "(" + value +
")";
}
}
public
override void Demarrer ( ) {
LancerEvent( );
}
public override
void Stopper ( ) {
//...
}
}
class UseVoiture {
// instanciation
d'une voiture particulière
static
void Main ( string [] args
) {
UnVehicule x
= new Voiture ( ) ;
x.TypeEngin
=
"Picasso" ; // propriété en écriture
System.Console.WriteLine ( "x est une " + x.TypeEngin )
; // propriété en lecture
System.Console.ReadLine ( ) ;
}
}
|
Résultats d'exécution :
1.9.1 Détails de fonctionnement
de la propriété TypeEngin en écriture
La propriété
TypeEngin est en écriture dans :
x.TypeEngin =
"Picasso" ;
Elle remonte à ses définitions successives
grâce l'utilisation du mot clef base qui
fait référence à la classe mère de la classe
en cours.
propriété TypeEngin dans la classe Voiture :
propriété TypeEngin dans la classe Terrestre
:
.........
propriété TypeEngin dans la classe UnVehicule
:
.....................
|
Définition de la propriété
dans la classe Voiture (écriture) :
base référence ici
la classe Terrestre.
|
Définition de la propriété
dans la classe Terrestre (écriture) :
base référence ici
la classe UnVehicule.
|
Définition de la propriété
dans la classe UnVehicule (écriture) :
nom est
le champ privé dans lequel est stocké la valeur effective de
la propriété.
|
1.9.2 Détails de fonctionnement de
la propriété TypeEngin en lecture
La propriété TypeEngin
est en lecure dans :
System.Console.WriteLine (
"x est une " + x.TypeEngin
) ;
Pour aller chercher la valeur effective, elle
remonte à ses définitions successives grâce l'utilisation
du mot clef base qui fait référence
à la classe mère de la classe en cours.
valeur transmise à partir de la classe Voiture :
|
Définition de la propriété
dans la classe Voiture (lecture) :
class Voiture :
Terrestre { ...
public override string
TypeEngin {
// redéfinition de propriété
get {
return base.TypeEngin +
"-voiture"; }
...
}
... }
L'accesseur get
va chercher le résultat dans base.TypeEngin et lui concatène le mot "-voiture".
base.TypeEngin référence
ici la propriété dans la classe Terrestre.
|
Définition de la propriété
dans la classe Terrestre (lecture) :
abstract class
Terrestre
: UnVehicule { ...
public override
string
TypeEngin {
// redéfinition de propriété
get {
return base.TypeEngin ; }
...
}
... }
L'accesseur get va chercher le
résultat dans base.TypeEngin.
base.TypeEngin référence
ici la propriété dans la classe UnVehicule.
|
Définition de la propriété
dans la classe UnVehicule (lecture) :
abstract class
UnVehicule : Vehicule , IVehicule { ...
private string
nom =
"";
public virtual
string
TypeEngin { // implantation virtuelle
de la propriété
get {
return nom ; }
...
}
... }
L'accesseur get
va chercher le résultat dans le champ nom.
nom est le champ privé dans
lequel est stocké la valeur effective de la propriété.
|
2. Les indexeurs
Nous savons en Delphi qu'il existe une notion de propriété
par défaut qui nous permet par exemple dans un objet Obj de type TStringList
se nomme strings, d'écrire Obj[5] au lieu de Obj.strings[5].
La notion d'indexeur de C# est voisine de cette notion de propriété
par défaut en Delphi.
2.1 Définitions et comparaisons avec les propriétés
Un indexeur est un membre de classe qui permet à un objet d'être
indexé de la même manière qu'un tableau. La signature
d'un indexeur doit être différente des signatures de tous les
autres indexeurs déclarés dans la même classe. Les indexeurs
et les propriétés sont très similaires de par leur concept,
c'est pourquoi nous allons définir les indexeurs à partir des
propriétés.
Tous les indexeurs sont représentés par l' opérateur
[ ] . Les liens sur les propriétés ou les indexeurs
du tableau ci-dessous renvoient directement au paragraphe associé.
2.1.1 Déclaration
Propriété
|
Indexeur
|
Déclarée par son
nom, avec champ de stockage :
private int champ;
public int propr1{
get {
return champ ; }
set
{ champ = value ; }
}
|
Déclaré par le mot
clef this, avec champ de stockage :
private int [ ] champ = new
int [10];
public int this [int index]{
get {
return champ[ index ] ; }
set
{ champ[ index ] = value ; }
}
|
2.1.2 Utilisation
Propriété
|
Indexeur
|
Déclaration :
class clA {
private int champ;
public int propr1{
get {
return champ ; }
set
{ champ = value ; }
}
}
Utilisation :
clA Obj = new clA( );
Obj.propr1 = 100 ;
int x = Obj.prop1
; // x = 100
|
Déclaration :
class clA {
private int [ ] champ =
new int [10];
public int this [int index]{
get {
return champ[ index ] ; }
set
{ champ[ index ] = value ; }
}
}
Utilisation :
clA Obj = new clA( );
for ( int i =0; i<5; i++
)
Obj[ i ] = i ;
int x = Obj[ 2 ]
; // x = 2
int y = Obj[ 3 ] ; // y = 3
...
|
2.1.3 Paramètres
Propriété
|
Indexeur
|
Déclaration :
class clA {
private int champ;
public int propr1{
get {
return champ*10 ; }
set
{ champ = value + 1 ; }
}
}
value est un paramètre implicite.
Utilisation :
clA Obj = new clA( );
Obj.propr1 = 100 ;
int x = Obj.prop1 ; // x = 1010
|
Déclaration :
class clA {
private int [ ] champ
= new int [10];
public int this [int k]{
get {
return champ[ k ]*10 ; }
set
{ champ[ k ] = value + 1 ; }
}
}
k est un paramètre formel de l'indexeur.
Utilisation :
clA Obj = new clA( );
for ( int i =0; i<5; i++ )
Obj[ i ] = i ;
int x = Obj[ 2 ] ; // x = 30
int y = Obj[ 3 ] ; // y = 40
...
|
2.1.4 Indexeur à liaison dynamique, abstraction
et interface
Reprenons l'exemple de hiérarchie de véhicules, traité
avec la propriété TypeEngin de type string, en y ajoutant un
indexeur de type string en proposant des définitions parallèles
à la propriété et à l'indexeur :
abstract class
Vehicule { // classe abstraite mère
....
}
|
interface IVehicule {
....
string TypeEngin
{ // déclaration
de propriété abstraite par défaut
get ;
set
;
}
....
string this [ int k ]
{ // déclaration
d'indexeur abstrait par défaut
get ;
set
;
}
....
}
|
abstract class
UnVehicule : Vehicule , IVehicule {
private
string
[ ] ArrayInfos = new
string
[10] ;
private string
nom =
"";
....
public virtual
string
TypeEngin { // implantation virtuelle
de la propriété
get
{
return nom ;
}
set { nom = "["+value+"]" ; }
}
....
public virtual
string this [ int k ] {
// implantation
virtuelle de l'indexeur
get {
return ArrayInfos[ k ] ;
}
set { ArrayInfos[ k ]
= value ; }
}
....
}
|
abstract class Terrestre
: UnVehicule {
private string
nomTerre =
"";
....
public override string
TypeEngin {
// redéfinition de propriété
get {
return base .TypeEngin
; }
set
{ string
nomTerre =
value
+ "-Terrestre";
base
.TypeEngin
= nomTerre ;
}
}
....
public override string this [ int k ]
{ // redéfinition
de l'indexeur
get {
return base[ k ] ; }
set
{ string
nomTerre =
value
+ "-Terrestre" ;
base[ k
] =
nomTerre + "/set =" + k.ToString( ) + "/" ; }
}
}
|
class Voiture : Terrestre {
public override
string
TypeEngin {
// redéfinition de propriété
get { return base.TypeEngin + "-voiture";
}
set
{ base.TypeEngin = "(" + value +
")";
}
}
public override
string
this [ int n ]
{ // redéfinition
de l'indexeur
get { return base[ n ] + "-voiture{get ="
+ n.ToString( ) + "}" ; }
set
{ base[ n ] = "(" + value +
")";
}
}
...
}
|