Passage par valeur ou référence
Passage par copie ou par référence ?
Passage par copie
En programmation, vous passez généralement vos variables à une méthode par copie.
Comme vu en classe, l'appel d'une méthode avec un paramètre de type int ne modifie pas la valeur de la variable dans la méthode Main(), et ce, même si les variables ont le même nom.
public static void Main(string[] args)
{
int a = 0;
M(a);
Console.WriteLine(a); // Ici, 'a' reste à 0.
}
public static void M(int a)
{
a = 8;
}
Cependant, cela devient un peu plus complexe lorsque vous travaillez avec des tableaux ou des objets.
public static void Main(string[] args)
{
int[] a = {0, 1, 2, 3};
M(a);
Console.WriteLine(a[0]); // Ici, 'a[0]' sera 8.
}
public static void M(int[] a)
{
a[0] = 8;
}
Voici un autre exemple pour illustrer le fait qu'il s'agit bien d'une copie de la référence, et non de la valeur :
public static void Main(string[] args)
{
int[] a = {0, 1, 2, 3};
M(a);
Console.WriteLine(a[0]); // Ici, 'a[0]' restera 0.
}
public static void M(int[] a)
{
a = new int[10]; // 'a' est maintenant une nouvelle référence en mémoire.
a[0] = 10; // Modifie uniquement ce nouveau tableau.
}
Passage par référence
Passage par référence avec le mot ref.
Il est également possible de demander à une méthode de modifier directement le contenu d'une variable, à l'endroit même où elle est stockée en mémoire. Pour ce faire, il faut spécifier que la variable doit être passée par référence.
Le mot-clé ref permet de passer une variable par référence.
public static void Main(string[] args)
{
int a = 3;
M(ref a); // L'appel se fait avec 'ref'
Console.WriteLine(a); // Ici, 'a' sera 5.
}
public static void M(ref int a) // La déclaration de 'a' se fait également avec 'ref'
{
a = 5; // 'a' est modifié directement dans la méthode Main.
}
Le mot-clé out
En C#, il existe également une autre façon de passer une variable par référence avec le mot-clé out.
Les mots-clés ref et out remplissent un rôle similaire, c'est-à-dire passer une variable par référence. La différence majeure réside dans le fait que ref nécessite que la variable soit initialisée avant l'appel de la méthode, tandis que out permet d'initialiser la variable directement dans la méthode appelée.
Cela vous rappelle-t-il quelque chose ?
Passage par référence avec le mot clé out
Voici un exemple utilisant out avec Int.TryParse :
public static void Main(string[] args)
{
int a; // Non initialisée
bool test = int.TryParse("42", out a); // 'a' sera initialisée ici.
Console.WriteLine(a); // Affichera 42.
}
De même, cela peut être appliqué aux tableaux et autres objets :
public static void Main(string[] args)
{
int[] a; // Non initialisé
M(out a); // 'a' sera initialisé dans M().
}
private static void M(out int[] a)
{
a = new int[] {1, 2, 3}; // Initialisation de 'a' dans M().
}
En revanche, essayer de faire la même chose avec ref provoquera une erreur de compilation, car ref exige que la variable soit déjà initialisée avant d'être passée à la méthode.
Résumé
- Passage par copie : La méthode reçoit une copie de la valeur de la variable.
Si la variable est un tableau ou un objet, la référence à cette mémoire est copiée,
ce qui permet de modifier les données, mais pas la référence elle-même.
- Passage par référence avec **ref** : Permet de modifier directement la variable
dans la méthode appelante. La variable est initialisée avant l'appel.
- Passage par référence avec **out** : Similaire à ref, mais la variable est
initialisée dans la méthode appelée. Vous ne pouvez pas l'utiliser sans l'initialiser dans la méthode.