Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

La différence entre les types Valeur et les types référence


Information sur le tutorial

Catégorie :.NET Tutorial .NET ( DotNet ) Date de création : 03/10/2007 16:15:29 Vu : 3 597 fois

Note :
Aucune note

Commentaire sur cette source (4)
Ajouter un commentaire et/ou une note


Description

Cette explication présente l'une des différences majeures qui existe entre les types référence et les types valeur en .net.

C'est quelque chose à savoir pour veux qui veulent passer les certifs un jour.

Tutorial

En c#, les pointeurs sont relativement transparents pour le développeur. C'est bien, mais cela signifie que certains concepts sous-jacents sont moins visibles.

 

Par exemple, en C/C++, pour qu'une méthode modifie la valeur d'une variable "i" de type int, il faut que l'on passe un pointeur vers cette variable. Pourquoi ? Parce que derrière le "i", on a directement sa valeur : 3 par exemple.

Lors de l'appel à la méthode, on copie cette valeur 3. La méthode pourra bien modifier le paramètre qu'on lui aura envoyé, elle ne touchera qu'à une copie de la donnée... et non à l'originale. De ce fait, notre "i" à nous reste bien à 3, même si la méthode s'amuse à remplacer ce 3 par un 9.

 

Avec l'utilisation des pointeurs, on envoie plus directement 3, mais une référence vers l'emplacement mémoire qui contient ce 3. On créé donc en quelque sorte une nouvelle variable qui contient une adresse vers l'emplacement mémoire qui contient le contenu de "i" (vous suivez ?). Encore une fois, lors de l'appel de la méthode, cette adresse est copiée puis passée à la méthode. Ce qui change, c'est que la méthode va pouvoir, grâce à cette adresse, aller modifier la valeur originale, et non sa copie.

 

En C#, c'est pareil, mais on en a moins conscience.

 

Prenons un exemple :

private void AjouteUn(int nb){

            nb++;

            Console.WriteLine("nb vaut : " + nb);

}

 

 

Soit l'algo suivant :

int i = 3;

Console.WriteLine("i vaut : " + nb);

AjouteUn(i);

Console.WriteLine("i vaut : " + nb);

 

La sortie de l'algo est la suivante :

i vaut 3

nb vaut 4

i vaut 3

 

 

Pourquoi i vaut-il 3 à la fin du prog ? Parceque la méthode AjouteUn a modifié la copie de la valeur 3 que nous lui avons passée en paramètre, mais elle n'a pas modifiée l'originale. D'ou le fait que "i" soit toujours égal à 3, même après l'appel de la méthode.

 

Si maintenant on a :

private void AjouteUn(ref int nb){

            nb++;

            Console.WriteLine("nb vaut : " + nb);

}

 

int i = 3;

Console.WriteLine("i vaut : " + nb);

AjouteUn(ref i);

Console.WriteLine("i vaut : " + nb);

 

La sortie est maintenant :

i vaut 3

nb vaut 4

i vaut 4

 

On a passé une référence (un pointeur) vers notre entier, donc notre méthode peut aller modifier la valeur de i (et non une copie), donc i est donc bien incrémentée de 1 même après la sortie de la méthode.

 

 

Venons en maintenant au but de l'article : la différence entre type valeur et type référence.

Derrière le nom d'une variable de type valeur ("i" dans l'exemple), on a directement une donnée concrète. Les types valeur sont les entiers, les singles, les floats, les longs... bref, tous les types "primitifs". Les enum sont aussi des types valeur, puisqu'un élément d'un enum peut se substituer à un entier. On a enfin les "instances" des structs (à ne pas confondre avec les instances de classes).

 

Par contre, si je déclare un objet complexe nommé "Obj" et de type Form, derrière le litéral obj, j'ai un pointeur (une référence) vers un emplacement mémoire contenant les données associées à mon objet Form. Les instances de classe sont donc des types référence.

 

2 conclusions importantes :

  • On doit mettre le mot clé « ref » sur un paramètre d'une méthode s'il s'agit d'un type valeur, et si la méthode doit avoir le pouvoir de modifier cette valeur. Dans tous les autres cas, PAS BESOIN. Si on passe une variable de type référence, la méthode pourra de toutes façons modifier les propriétés de l'objet (on passe une référence, un pointeur).
  • A chaque fois que l'on appelle une méthode, le framework .net copie tous les arguments de l'appelant et donne ces copies à la méthode. Ceci est vrai dans tous les cas, qu'il s'agisse d'entiers (types valeur), d'instances de classe (concrètement une référence vers un emplacement mémoire), ou que sais-je encore.
signaler à un administrateur
Commentaire de leprov le 09/10/2007 15:57:08

quelques commentaires :
1 - ce tutoriel est redondant avec un autre déjà existant (fait par bidou je crois)
2 - dire que l'utilisation de ref sur un type référence ne sert a rien est faux! c'est inutile dans LA PLUPART des cas, mais en C++ on utilise bien des XXX** (avec XXX un type quelconque)...ici c'est pareil...ca peut servir dans certains cas très particuliers (et aussi très rares) pour des optimisations.

signaler à un administrateur
Commentaire de yoannd le 09/10/2007 16:36:38

Quelques commentaires sur ton commentaire :
1 - Tu dois certainement parler de ce tutoriel (que je n'avais pas vu) :
http://www.csharpfr.com/tutoriaux/PASSAGE-REFERENCE-VALEUR_659.aspx

Mon tuto était plus "en réponse" à cette source, à laquelle je souhaitais apporter quelques précisions :
http://www.csharpfr.com/codes/PASSAGE-REFERENCE_11473.aspx

MAIS... La prochaine fois que tu dis qu'un tutoriel est redondant, essaye de faire 2 choses :
Primo : donner la référence de l'article en question,
Secondo : pense à la personne qui a écrit le tutorial "redondant" en te demandant si le dépot de ce tuto/source ne partait pas d'une bonne intention.
Pour ma part, j'ai passé un peu de temps à écrire ce tuto, et même si ta remarque est fondée, ça m'ennerve un peu de voir le ton de ton commentaire.

2 - Pourrais-tu donner un exemple concret d'utilisation utile d'un ref sur un type référence ?
Si tu passes un objet de type "Obj" en utilisant le mot clé "ref", tu créées une référence vers une référence déjà existante des données de la classe "Obj". Tu copies ensuite cette référence de référence vers "obj" que tu envoies à la méthode. Mes questions sont donc :
- En quoi copier directement la référence est-il moins avantageux, et quels sont les cas ?
- Quel eset selon toi le gain de passer une instance de classe par "ref" ?

Pour résumer, te serait-il possible d'être un peu plus constructif dans tes commentaires ?

signaler à un administrateur
Commentaire de ffmic86 le 18/04/2008 11:44:46

Je me lance sur le C# et c'était utile d'apprendre l'utilisation des ref, merci yoannd .

signaler à un administrateur
Commentaire de leprov le 15/05/2008 14:28:42

oulah, javais oublié que j'avais répondu a ce tuto. tout d'abord excuse moi si ma réponse t'avais paru sèche, ce n'etait absolument pas dans mon intention.
Ensuite, pour répondre a ta question sur l'utilisation de ref sur un type référence, je parle d'optimisations (bien que ce ne soit pas le seul cas, mais cest pour moi le plus fréquent).

Bref, sans parler d'optimisations, il y a le cas des types références que tu veux déréférencer dans ta fonction tout en modifiant tout de même l'objet passé en paramètre. un exemple simple et courant : tu passe une string en paramètre et tu veux modifier cette string. l'opérateur = est surchargé, et faire qqch qui ressemble a
void foo(string s)
{
s = "test";
}

cette appel modifie s uniquement de facons locale. en effet, cela revient a faire s = new string("test"). Le pointeur sur s est donc modifié. cependant, le pointeur passé en paramètre est une copie du pointeur. modifier ce pointeur implique que les futures modifications ne seront que locales a la fonction. en passant la string par reference, le pointeur est lui meme passé par référence, et la modification de ce pointeur a donc une portée globale.


En ce qui concerne les optimisations, le principe est le meme. je veux passer une liste par référence a une fonction. dans un cas simple, je ne fais que modifier une valeur. dans ce cas pas de problèmes. cependant, dans d'autres cas, je veux complètement recréer une autre liste. il sera plus efficace du point de vue du programmeur de simplement créer une nouvelle instance et de modifier la liste référencée, plutot que de vider la première et la reremplir (cest peut etre différent niveau performances, quoi que, mais la n'est pas la question, ceci n'est qu'un exemple). Ainsi, il peut etre rentable de passer la liste par référence.

Désolé de pas avoir répondu avant, j''avais complètement zappé ce tuto

Ajouter un commentaire



Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,250 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.