web-dev-qa-db-fra.com

Objet passé en paramètre à une autre classe, par valeur ou référence?

En C #, je sais que par défaut, tous les paramètres passés dans une fonction se font par copie, c'est-à-dire qu'au sein de la fonction, il y a une copie locale du paramètre. Mais qu'en est-il lorsqu'un objet est passé en paramètre à une autre classe?

Un scénario comme le suivant serait-il transmis par référence ou par valeur:

class MyClass {
   private Object localObj;

   public void SetObject(Object obj) {
      localObj = obj;
   }
}

void Main() {
   Object someTestObj = new Object();
   someTestObj.name = "My Name";
   MyClass cls = New MyClass();
   cls.SetObject(someTesetObj);
}

Dans ce cas, la variable de classe localObj aurait-elle la même copie que la someTestObj créée dans la classe de pilote Main? Ou les deux variables pointeraient-elles vers une instance d'objet différente?

15
Carven

Les objets seront passés par référence indépendamment des méthodes internes de la même classe ou d'une autre classe. Voici une version modifiée du même exemple de code pour vous aider à comprendre. La valeur sera modifiée en "xyz".

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public class Employee
    {
        public string Name { get; set; }
    }

    public class MyClass
    {
        public Employee EmpObj;

        public void SetObject(Employee obj)
        {
            EmpObj = obj;
        }
    }

    public class Program
    {
       static void Main(string[] args)
        {
            Employee someTestObj = new Employee();
            someTestObj.Name = "ABC";

            MyClass cls = new MyClass();
            cls.SetObject(someTestObj);

            Console.WriteLine("Changing Emp Name To xyz");
            someTestObj.Name = "xyz";

            Console.WriteLine("Accessing Assigned Emp Name");
            Console.WriteLine(cls.EmpObj.Name); 

           Console.ReadLine();
       }       
    }
 }
8
Rajee

Les "objets" ne sont JAMAIS transmis en C # - les "objets" ne sont pas des valeurs dans le langage. Les seuls types du langage sont les types primitifs, les types struct, etc. et les types de référence . Pas de "types d'objet".

Les types Object, MyClass, etc. sont des types de référence. Leurs valeurs sont des "références" - des pointeurs vers des objets. Les objets ne peuvent être manipulés que par des références - lorsque vous faites new dessus, vous obtenez une référence, le . l'opérateur opère sur une référence; etc. Il n'y a aucun moyen d'obtenir une variable dont la valeur "est" un objet, car il n'y a aucun type d'objet.

Tous les types, y compris les types de référence, peuvent être passés par valeur ou par référence. Un paramètre est passé par référence s'il a un mot clé comme ref ou out. Le paramètre SetObject de la méthode obj (qui est de type référence) n'a pas un tel mot-clé, il est donc passé par valeur - la référence est passée par valeur.

15
newacct

En supposant que someTestObj est un class et non un struct, l'objet est passé par référence, ce qui signifie que obj et someTestObj font référence au même objet. Par exemple. changer name dans l'un le changera dans l'autre. Cependant, contrairement à ce que vous avez réussi en utilisant le mot clé ref , définissez obj = somethingElse ne changera pas someTestObj.

4
Tim S.

J'ai trouvé les autres exemples peu clairs, j'ai donc fait mon propre test qui a confirmé qu'une instance de classe est passée par référence et que de telles actions effectuées sur la classe affecteront l'instance source.

En d'autres termes, ma méthode Increment modifie son paramètre myClass à chaque appel.

class Program
{
    static void Main(string[] args)
    {
        MyClass myClass = new MyClass();
        Console.WriteLine(myClass.Value);  // Displays 1
        Increment(myClass);
        Console.WriteLine(myClass.Value);  // Displays 2
        Increment(myClass);
        Console.WriteLine(myClass.Value);  // Displays 3           
        Increment(myClass);
        Console.WriteLine(myClass.Value);  // Displays 4
        Console.WriteLine("Hit Enter to exit.");
        Console.ReadLine();
    }

    public static void Increment(MyClass myClassRef)
    {
        myClassRef.Value++;
    }
}

public class MyClass
{
    public int Value {get;set;}
    public MyClass()
    {
        Value = 1;
    }
}
4
RitchieD

Un objet s'il est passé en tant que type de valeur, les modifications apportées aux membres de l'objet à l'intérieur de la méthode sont également impactées en dehors de la méthode. Mais si l'objet lui-même est défini sur un autre objet ou réinitialisé, il ne sera pas reflété en dehors de la méthode. Je dirais donc que l'objet dans son ensemble est transmis en tant que type de valeur uniquement, mais les membres de l'objet sont toujours de type référence.

        private void button1_Click(object sender, EventArgs e)
    {
        Class1 objc ;
         objc = new Class1();
        objc.empName = "name1";
        checkobj( objc);
        MessageBox.Show(objc.empName);  //propert value changed; but object itself did not change
    }
    private void checkobj ( Class1 objc)
    {
        objc.empName = "name 2";
        Class1 objD = new Class1();
        objD.empName ="name 3";
        objc = objD ;
        MessageBox.Show(objc.empName);  //name 3
    }
2
sjd

En général, un "objet" est une instance d'une classe, qui est une "image"/"empreinte digitale" d'une classe créée en mémoire (via un nouveau mot-clé).
La variable de type d'objet fait référence à cet emplacement de mémoire, c'est-à-dire qu'elle contient essentiellement l'adresse en mémoire.
Ainsi, un paramètre de type d'objet transmet une référence/"lien" à un objet, pas une copie de l'objet entier.

0
Pavel Jablonský

Si vous avez besoin de copier un objet, veuillez vous référer au clonage d'objet, car les objets sont passés par référence, ce qui est bon pour les performances d'ailleurs, la création d'objet coûte cher.

Voici l'article auquel se référer: Objets de clonage profond

0
Farfarak