• Aucun résultat trouvé

La conversion entre les objets avec le casting

Nous avons déjà vu dans la partie précédente qu’il était possible de convertir les types qui se ressemblent entre eux. Cela fonctionne également avec les objets.

Plus précisément, cela veut dire que nous pouvons convertir un objet en un autre seulement s’il est une sorte de l’autre objet. Nous avons vu dans les chapitres précédents qu’il s’agissait de la notion d’héritage.

Ainsi, si nous avons défini une classe Animal et que nous définissons une classe Chien qui hérite de cette classe Animal :

Code : C#

public class Animal {

}

public class Chien : Animal {

nous pourrons alors convertir le chien en animal dans la mesure où le chien est une sorte d’animal :

Code : C#

Chien medor = new Chien(); Animal animal = (Animal)medor;

Nous utilisons pour ce faire un cast, comme nous l’avons déjà fait pour les types intégrés (int, bool, etc.). Il suffit de préfixer la variable à convertir du type entre parenthèses dans lequel nous souhaitons le convertir. Ici, nous pouvons convertir facilement notre Chien en Animal.

Par contre, il est impossible de convertir un chien en voiture, car il n’y a pas de relation d’héritage entre les deux. Ainsi les instructions suivantes :

Code : C#

Chien medor = new Chien();

Voiture voiture = (Voiture)medor;

provoqueront une erreur de compilation.

Nous avons précédemment utilisé l’héritage afin de mettre des chiens et des chats dans une liste d’animaux. Nous avions fait quelque chose du genre :

Code : C#

List<Animal> animaux = new List<Animal>(); Animal chien = new Chien();

Animal chat = new Chat(); animaux.Add(chien);

animaux.Add(chat);

Il serait plus logique en fait d’écrire les instructions suivantes :

Code : C#

List<Animal> animaux = new List<Animal>(); Chien chien = new Chien();

Chat chat = new Chat(); animaux.Add((Animal)chien); animaux.Add((Animal)chat);

Dans ce cas, nous créons un objet Chien et un objet Chat que nous mettons dans une liste d’objets Animal grâce à une conversion utilisant un cast.

En fait, ce cast est inutile et nous pouvons simplement écrire :

Code : C#

animaux.Add(chien); animaux.Add(chat);

La conversion est implicite, comme lorsque nous avions utilisé un object en paramètres d’une méthode et que nous pouvions lui passer tous les types qui dérivent d’ object.

Nous avions également vu que nous ne pouvions traiter les chiens et les chats que comme des animaux à partir du moment où nous les mettions dans une liste. Avec les objets suivants :

Code : C#

public class Animal {

public void Respirer() {

Console.WriteLine("Je respire"); }

}

public class Chien : Animal {

public void Aboyer() {

Console.WriteLine("Waouf"); }

}

public class Chat : Animal {

public void Miauler() {

Console.WriteLine("Miaou"); }

}

Nous pouvions utiliser une boucle pour faire respirer tous nos animaux :

Code : C#

List<Animal> animaux = new List<Animal>(); Chien chien = new Chien();

Chat chat = new Chat(); animaux.Add(chien); animaux.Add(chat);

foreach (Animal animal in animaux) {

animal.Respirer(); }

Mais impossible de faire aboyer le chien, ni miauler le chat.

Si vous tentez de remplacer dans la boucle Animal par Chien, avec :

Code : C#

foreach (Chien c in animaux) {

}

Vous pourrez faire aboyer le premier élément de la liste qui est effectivement un chien, par contre il y aura un plantage au deuxième élément de la liste car il s’agit d’un chat :

Lorsque notre programme a tenté de convertir un animal qui est un chat en chien, il nous a fait comprendre qu’il n’appréciait que moyennement. Les chiens n’aiment pas trop les chats d’une manière générale, alors en plus, un chat qui essaie de se faire passer pour un chien : c’est une déclaration de guerre !

Voilà pourquoi notre programme a levé une exception. Il lui était impossible de convertir un Chat en Chien.

Il est cependant possible de tester si une variable correspond à un objet grâce au mot-clé is. Ce qui nous permettra de faire la conversion adéquate et de nous éviter une erreur à l’exécution :

Code : C#

foreach (Animal animal in animaux) { if (animal is Chien) { Chien c = (Chien)animal; c.Aboyer(); } if (animal is Chat) { Chat c = (Chat)animal; c.Miauler(); } }

Nous testons avec le mot-clé is si l’animal est une instance d’un Chien ou d’un chat. Le code du dessus nous permettra d’utiliser dans la boucle l’animal courant comme un chien ou un chat en fonction de ce qu’il est vraiment, grâce au test. Ce qui produira :

Le fait de tester ce qu’est vraiment l’animal avant de le convertir est une sécurité indispensable pour éviter le genre d’erreur du dessus.

C’est l’inconvénient du cast explicite. Il convient très bien si nous sommes certains du type dans lequel nous souhaitons en convertir un autre. Par contre, si la conversion n’est pas possible, alors nous aurons une erreur.

Lorsque nous ne sommes pas certains du résultat du cast, mieux vaut tester si l’instance d’un objet correspond bien à l’objet lui- même.

Cela peut se faire comme nous l’avons vu avec le mot-clé is, mais également avec un autre cast qui s’appelle le cast dynamique. Il se fait en employant le mot-clé as.

Ce cast dynamique vérifie que l’objet est bien convertible. Si c’est le cas, alors il fait un cast explicite pour renvoyer le résultat de la conversion, sinon, il renvoie une référence nulle.

Le code du dessus peut donc s’écrire :

Code : C#

foreach (Animal animal in animaux) {

Chien c1 = animal as Chien; if (c1 != null)

{

c1.Aboyer(); }

Chat c2 = animal as Chat; if (c2 != null)

{

c2.Miauler(); }

}

On utilise le mot-clé as en le faisant précéder de la valeur à tenter de convertir et en le faisant suivre du type dans lequel nous souhaitons la convertir.

Fonctionnellement, nous faisons la même chose dans les deux codes. Vous pouvez choisir l’écriture que vous préférez, mais sachez que c’est ce dernier qui est en général utilisé car il est préconisé par Microsoft et est un tout petit peu plus performant. Un petit détail encore. Il est possible de convertir un type valeur, comme un int ou un string en type référence en utilisant ce qu’on appelle le boxing. Rien à voir avec le fait de taper sur les types valeur. Comme nous l’avons vu, les types valeur et les types référence sont gérés différemment par .NET. Aussi, si nous convertissons un type valeur en type référence, .NET fait une

opération spéciale automatiquement. Ainsi le code suivant :

Code : C#

int i = 5;

object o = i; // boxing

effectue un boxing automatique de l’entier en type référence. C’est ce boxing automatique qui nous permet de manipuler les types valeur comme des object.

C’est aussi ce qui nous a permis plus haut de passer un entier en paramètre à une méthode qui acceptait un object. En interne, ce qu’il se passe c’est que object se voit attribuer une référence vers une copie de la valeur de i. Ainsi, modifier o ne modifiera pas i. Ce code :

Code : C# int i = 5; object o = i; // boxing o = 6; Console.WriteLine(i); Console.WriteLine(o); affiche 5 puis 6.

Le contraire est également possible, ce qu’on appelle l’unboxing. Seulement, celui-ci a besoin d’un cast explicite afin de pouvoir compiler. C'est-à-dire :

Code : C#

int i = 5;

object o = i; // boxing

int j = (int)o; // unboxing

ici nous reconvertissons la référence vers la valeur de o en entier et nous effectuons à nouveau une copie de cette valeur pour la mettre dans j. Ainsi le code suivant :

Code : C#

int i = 5;

object o = i; // boxing

o = 6;

int j = (int)o; // unboxing

j = 7;

Console.WriteLine(i); Console.WriteLine(o); Console.WriteLine(j);

affichera en toute logique 5 puis 6 puis 7.

À noter que ces opérations sont chronophages, elles sont donc à faire le moins possible.

Les objets peuvent être des types valeur ou des types référence. Les variables de type valeur possèdent la valeur de l'objet, comme un entier. Les variables de type référence possèdent une référence vers l'objet en mémoire.

Tous les objets dérivent de la classe de base Object.

On peut substituer une méthode grâce au mot-clé override si elle s'est déclarée candidate à la substitution grâce au mot-clé virtual.

La surcharge est le polymorphisme permettant de faire varier les types des paramètres d'une même méthode ou leurs nombres.