Mes deux cents sur Deep Copy vs Shallow Copy dans .Net

Microsoft .Net prend en charge le clonage d'objets - une capacité à créer une copie exacte d'un objet (également appelé clone). Le clonage peut être de deux types: copie superficielle et copie profonde. Alors que le premier peut être implémenté en appelant la méthode MemberwiseClone de la classe System.Object, l'implémentation de la dernière est un peu délicate car vous ne l'avez pas pris en charge dans le framework par défaut. En substance, alors qu'une copie superficielle copie les références sans les objets référencés, un clone profond crée une copie de l'objet source avec ses références.

Quelles sont toutes les options disponibles pour le clonage?

Pour cloner une instance d'une classe en C #, vous avez le choix entre plusieurs options. Ceux-ci comprennent les éléments suivants:

  • Utilisation de la méthode System.Object.MemberwiseClone pour effectuer une copie superficielle
  • Utilisation de Reflection en tirant parti de la méthode Activator.CreateInstance
  • Utilisation de la sérialisation
  • En implémentant l'interface IClonable

Notez que lors du clonage d'objets ou d'instances de classes dans .Net, vous n'avez pas besoin de prendre en compte les membres statiques ou les champs statiques. La raison en est que les objets statiques sont stockés dans un emplacement de mémoire partagée et qu'un emplacement de mémoire leur est alloué par domaine d'application.

Copie superficielle vs copie profonde

Considérez une classe Employee et que nous créons une instance de la classe Employee comme indiqué ci-dessous.

Employee emp = new Employee();

Employee clone = emp;

Reportez-vous à l'extrait de code ci-dessus. L'opérateur d'affectation "=" copierait la référence et non l'objet réel. La méthode MemberwiseClone () définie dans la classe System.Object fait exactement la même chose. Ce sont des exemples de copie superficielle. Par conséquent, lorsque vous utilisez un opérateur d'affectation pour copier et vous opposer à un autre ou, utilisez la méthode Memberwise.Clone (), vous faites en fait une copie superficielle de l'objet.

Alors que dans une copie superficielle, les membres de l'objet copié font référence au même objet que l'objet d'origine, dans une copie complète, des instances distinctes de chacun des membres du type de référence dans l'instance d'origine sont créées dans l'instance nouvelle ou clonée. Par conséquent, si vous avez un type de référence dans l'instance d'origine, la nouvelle instance contiendra également le même membre de type de référence, mais ce type de référence pointera vers une toute nouvelle instance.

Dans une copie superficielle, un nouvel objet est créé, puis les membres non statiques de l'objet source sont copiés vers l'objet cible ou le nouvel objet. Si le membre est un champ de type valeur, une copie bit par bit du champ est effectuée. En revanche, si le membre copié est un type référence, la référence est copiée. Par conséquent, le membre de référence à l'intérieur de l'objet d'origine et les objets cibles font référence au même objet dans la mémoire.

Si vous avez une collection avec des éléments individuels à l'intérieur et que vous souhaitez effectuer une copie superficielle de l'instance de collection. Il convient de noter qu'une copie superficielle d'une instance de collection copie la structure de la collection mais pas les éléments à l'intérieur de la collection. Par conséquent, après avoir effectué une copie superficielle de l'instance de collection, vous auriez deux collections partageant les éléments individuels de la collection. Au contraire, si vous effectuez une copie complète de l'instance de collection, vous auriez deux instances de collection avec les éléments individuels de la collection d'origine dupliqués.

Implémentation de la copie profonde à l'aide de la sérialisation

Vous pouvez implémenter la copie profonde de plusieurs manières. L'une des méthodes les plus préférées pour implémenter une copie complète d'un objet consiste à utiliser la sérialisation. Vous pouvez également tirer parti de la réflexion pour effectuer une copie complète d'une instance d'une classe. L'extrait de code suivant illustre comment vous pouvez écrire une méthode qui implémente la sérialisation binaire pour effectuer une copie complète d'une instance à l'aide de C #.

public static T DeepCopy(T obj)

       {

           if (!typeof(T).IsSerializable)

           {

               throw new Exception("The source object must be serializable");

           }

           if (Object.ReferenceEquals(obj, null))

           {

               throw new Exception("The source object must not be null");

           }

           T result = default(T);

           using (var memoryStream = new MemoryStream())

           {

                var formatter = new BinaryFormatter();

               formatter.Serialize(memoryStream, obj);

               memoryStream.Seek(0, SeekOrigin.Begin);

               result = (T)formatter.Deserialize(memoryStream);

               memoryStream.Close();

           }

           return result;

       }

Étant donné que vous avez une classe d'entité appelée Employee, vous pouvez effectuer une copie complète d'une instance de la classe Employee comme indiqué dans l'extrait de code ci-dessous.

static void Main(string[] args)

       {

           Employee emp = new Employee();

           emp.EmployeeId = 1;

           emp.FirstName = "Joydip";

           emp.LastName = "Kanjilal";

           Employee clone = DeepCopy(emp);

           if(Object.ReferenceEquals(emp, clone))

           {

               Console.WriteLine("References are the same.");

           }

           else

           {

               Console.WriteLine("References are different.");

           }

       }

Lorsque vous exécutez le programme ci-dessus, une copie complète de l'instance «emp» est effectuée et le message «Les références sont différentes». sera affiché.