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 !

METHODE CLONAGE 'DEEPCLONAGE'


Information sur la source

Catégorie :Astuces Source .NET ( DotNet ) Classé sous : clone, icloneable, child, deep Niveau : Débutant Date de création : 30/11/2005 Date de mise à jour : 30/11/2005 14:06:40 Vu / téléchargé: 12 574 / 156

Note :
9 / 10 - par 1 personne
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

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


Description

MemberwiseClone est pratique, certes, mais elle ne duplique pas les propriétés et fields de type reference : l'objet cloné pointe sur les mêmes objets...
Il est bien sur de définir la méthode Clone pour chacun des 'enfant', et les appeler les uns après les autres.
seulement, si vous ajouter un champs, il faudra penser a modifier en conséquence votre méthode Clone...

je vous propose donc cette classe, a utiliser en tant que classe de base de vos classes à cloner.
Celle-ci implémente la méthode Clone, et parcoure un à un les fields et properties qu'elle contient, et clone le tout.
(Les IEnumerables ne sont pas pris en compte, je pourrais modifier mon code, au besoin)

 

Source

  • using System;
  • using System.Reflection;
  • public abstract class CDeepCloner : ICloneable
  • {
  • private object Clone(object vObj)
  • {
  • if (vObj.GetType().IsValueType || vObj.GetType() == Type.GetType("System.String"))
  • return vObj;
  • else
  • {
  • object newObject = Activator.CreateInstance(vObj.GetType());
  • foreach (PropertyInfo Item in newObject.GetType().GetProperties())
  • {
  • if (Item.GetType().GetInterface("ICloneable") != null)
  • {
  • ICloneable IClone = (ICloneable)Item.GetValue(vObj, null);
  • Item.SetValue(newObject, IClone.Clone(), null);
  • }
  • else
  • Item.SetValue(newObject, Clone(Item.GetValue(vObj, null)), null);
  • }
  • foreach (FieldInfo Item in newObject.GetType().GetFields())
  • {
  • if (Item.GetType().GetInterface("ICloneable") != null)
  • {
  • ICloneable IClone = (ICloneable)Item.GetValue(vObj);
  • Item.SetValue(newObject, IClone.Clone());
  • }
  • else
  • Item.SetValue(newObject, Clone(Item.GetValue(vObj)));
  • }
  • return newObject;
  • }
  • }
  • public object Clone()
  • {
  • return Clone(this);
  • }
  • }
using System;
using System.Reflection;

public abstract class CDeepCloner : ICloneable
{
    private object Clone(object vObj)
    {
        if (vObj.GetType().IsValueType || vObj.GetType() == Type.GetType("System.String"))
            return vObj;
        else
        {
            object newObject = Activator.CreateInstance(vObj.GetType());

            foreach (PropertyInfo Item in newObject.GetType().GetProperties())
            {
                if (Item.GetType().GetInterface("ICloneable") != null)
                {
                    ICloneable IClone = (ICloneable)Item.GetValue(vObj, null);
                    Item.SetValue(newObject, IClone.Clone(), null);
                }
                else
                    Item.SetValue(newObject, Clone(Item.GetValue(vObj, null)), null);
            }

            foreach (FieldInfo Item in newObject.GetType().GetFields())
            {
                if (Item.GetType().GetInterface("ICloneable") != null)
                {
                    ICloneable IClone = (ICloneable)Item.GetValue(vObj);
                    Item.SetValue(newObject, IClone.Clone());
                }
                else
                    Item.SetValue(newObject, Clone(Item.GetValue(vObj)));
            }
            return newObject;
        }
    }

    public object Clone()
    {
        return Clone(this);
    }
}

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

30 novembre 2005 14:06:41 :
J'ai ajoute le clonage des fields et propriétés privées

Commentaires et avis

signaler à un administrateur
Commentaire de sebmafate le 30/11/2005 16:14:43 administrateur CS

Nickel... mais n'oublie pas de cocher la case 'Ceci est une source .net' ;)

signaler à un administrateur
Commentaire de Renfield le 30/11/2005 16:43:45 administrateur CS

Je suis en train de gonfler la classe, avec la gestion des tableaux, etc...

désolé pour la case .Net .... j'avais pas fais gaffe à sa présence, je veux dire, C# implique .Net (enfin, me semble-t'il ^^)

signaler à un administrateur
Commentaire de sebmafate le 30/11/2005 16:51:04 administrateur CS

oui et non... comme on me l'a fait remarqué y a pas si longtemps... C# peut aussi vouloir Mono... ou tout autre chose... du moment qu'il existe un compilateur...

signaler à un administrateur
Commentaire de TheSaib le 01/12/2005 00:12:37 administrateur CS

En terme de perf çà donne quoi ?

signaler à un administrateur
Commentaire de Renfield le 01/12/2005 00:16:38 administrateur CS

moins rapide, je suppose, que de tout cloner soit-même, invoquant en cascade, la methode Clone des Classes filles qui le supporte
reste que là, les fistons sont bien clonés, et que l'on a pas a y retoucher sans cesse...

signaler à un administrateur
Commentaire de TheSaib le 01/12/2005 00:21:25 administrateur CS

Tu as benchmarqué ou pas ?
Si à l'occasion tu le fais ca m'interresserait :)

signaler à un administrateur
Commentaire de Bubuss le 08/08/2006 11:07:30

Chapeau pour ce code, je l'ai intégré au mien mais comme mes classes héritaient déjà dune autre classe j'ai juste récupérer ta fonction et je l'appelle ponctuellement! ça marche très bien!

Je signale cependant un bug car pour certaine propriété de mes objets je n'avais aucune instanciation de faite donc j'ai rajouté après le premier foreach item:

if (Item.GetValue(vObj, null) != null)
{
(... code ...)
}

Voilà je te remercie pour le partage de ce code Salut!

PS : Je crois que cette vérification est nécessaire seulement dans le premier foreach car je ne penses pas que les champs peuvent être = null

signaler à un administrateur
Commentaire de spikeyz le 28/08/2006 16:46:46

Voila moi je viens de finir une methode un peu plus complete que celle-ci si ca interresse quelqu'un.

public object Clone()
        {
            //Creation de la nouvelle instance de l'objet
            Object newObject = Activator.CreateInstance(this.GetType());

            //Recuperation de toutes les proprietes de l'objet
            PropertyInfo[] infos = newObject.GetType().GetProperties();

            foreach (PropertyInfo info in infos)
            {
                //Test de la propriete pour savoir si elle supporte l'interface ICloneable
                Type ICloneType = info.PropertyType.GetInterface("ICloneable", true);

                if (ICloneType != null)
                {
                    //Recuperation de l'interface ICloneable de l'objet
                    ICloneable IClone = (ICloneable)info.GetValue(this, null);

                    //utilisation de la methode clone() pour assigner la nouvelle valeur de la propriete
                    info.SetValue(newObject, IClone.Clone(), null);
                }
                else
                    //Si la propriete ne supporte pas l'interface, assignation juste de la valeur
                    info.SetValue(newObject, info.GetValue(this, null), null);

                //Test de la propriete pour savoir si elle supporte l'interface IEnumerable
                Type IEnumerabletype = info.PropertyType.GetInterface("IEnumerable", true);

                if (IEnumerabletype != null)
                {
                    //Recuperation de l'interface IEnumerable de la propriete
                    IEnumerable IEnum = (IEnumerable)info.GetValue(this, null);

                    Type IListType = info.PropertyType.GetInterface("IList", true);
                    Type IDicType = info.PropertyType.GetInterface("IDictionary", true);

                    int j = 0;

                    if (IListType != null)
                    {
                        //recuperation de l'interface IList
                        IList list = (IList)info.GetValue(newObject,null);

                        foreach (Object obj in IEnum)
                        {
                            //Test de l'objet pour savoir si il supporte l'interface ICloneable
                            ICloneType = obj.GetType().GetInterface("ICloneable", true);

                            if (ICloneType != null)
                            {
                                ICloneable clone = (ICloneable)obj;
                                list[j] = clone.Clone();
                            }
                            j++;
                        }
                    }
                    else if (IDicType != null)
                    {
                        //Recuperation de l'interface IDictionary
                        IDictionary dic = (IDictionary)info.GetValue(newObject,null);

                        j = 0;

                        foreach (DictionaryEntry de in IEnum)
                        {
                            //Test de l'objet pour savoir si il supporte l'interface ICloneable
                            ICloneType = de.Value.GetType().GetInterface("ICloneable", true);

                            if (ICloneType != null)
                            {
                                ICloneable clone = (ICloneable)de.Value;
                                dic[de.Key] = clone.Clone();
                            }
                            j++;
                        }
                    }
                }
            }

            //Recuperation de tous les champs de cette instance
            FieldInfo[] fields = newObject.GetType().GetFields();

            foreach (FieldInfo fi in this.GetType().GetFields())
            {
                //Test du champs pour savoir si il supporte l'interface ICloneable
                Type ICloneType = fi.FieldType.GetInterface("ICloneable", true);

                if (ICloneType != null)
                {
                    //Recuperation de l'interface ICloneable de l'objet
                    ICloneable IClone = (ICloneable)fi.GetValue(this);

                    //utilisation de la methode clone() pour assigner la nouvelle valeur du champs
                    fi.SetValue(newObject, IClone.Clone());
                }
                else
                {
                    //Si le champs ne supporte pas l'interface, assignation juste du champs
                    fi.SetValue(newObject, fi.GetValue(this));
                }

                //Test du champs pour savoir si il support l'interface IEnumerable
                Type IEnumerabletype = fi.FieldType.GetInterface("IEnumerable", true);

                if (IEnumerabletype != null)
                {
                    //Recuperation de l'interface IEnumerable du champs
                    IEnumerable IEnum = (IEnumerable)fi.GetValue(this);

                    Type IListType = fi.FieldType.GetInterface("IList", true);
                    Type IDicType = fi.FieldType.GetInterface("IDictionary", true);

                    int j = 0;

                    if (IListType != null)
                    {
                        //recuperation de l'interface IList
                        IList list = (IList)fi.GetValue(newObject);

                        foreach (Object obj in IEnum)
                        {
                            //Test de l'objet pour savoir si il supporte l'interface ICloneable
                            ICloneType = obj.GetType().GetInterface("ICloneable", true);

                            if (ICloneType != null)
                            {
                                ICloneable clone = (ICloneable)obj;
                                list[j] = clone.Clone();
                            }
                            j++;
                        }
                    }
                    else if(IDicType != null)
                    {
                        //Recuperation de l'interface IDictionary
                        IDictionary dic = (IDictionary)fi.GetValue(newObject);

                        j = 0;

                        foreach (DictionaryEntry de in IEnum)
                        {
                            //Test de l'objet pour savoir si il supporte l'interface ICloneable
                            ICloneType = de.Value.GetType().GetInterface("ICloneable", true);

                            if (ICloneType != null)
                            {
                                ICloneable clone = (ICloneable)de.Value;
                                dic[de.Key] = clone.Clone();
                            }
                        j++;
                        }
                    }
                }
            }
            return newObject;
        }

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

relation MDI child / parent [ par zouzounet ] bonjour :)tout d'abord, bonnes paques à tous :)j'ai ensuite une tite question qui me tracasse mon code :je suis sur une appli mdi, avec des child... l Communication inter-Fenetre (MDI Child vers Parent) [ par Neptune84 ] Je voudrais faire la chose suivante :WinFormPrinc est la fenetre Parent avec un menu menuItem6. Ce menu ouvre (Création) une fenetre MessageUn. Le pro clone d'un controle [ par Fildomen ] sltj'ai un panel ou ya presque 5 controles, et se panel je doit le cloner 5 fois, et pour chacune, je modifierai le panel,comment faire stp pour clone PQ ListViewItem.Clone() ne clone pas tout ? [ par disolheid ] Bonjour (bonsoir) à tous,Pourriez vous me dire pq : ListViewItem clone = (ListViewItem)lvi.Clone();les propriétés "imageindex", "text", Liens entre MDI Child [ par dals ] Salut à tous ceux qui liront mon msg!!! Je débute en VB .Net et mon soucis est d'arriver à établir un lien entre 2 de mes fen&#234 Overwrite de la méthode Clone() [ par Globinours ] Voilà mon problème est simple je veux cloner des TreeNode mais ensuite le casté dans un type dérivant de TreeNode qui contient seu Clone de collection [ par zebobo5 ] Bijour bijour tt le monde Dites comment fait-on pour cloner une collection, g un peu la flème de me tapper tt un traitement. Merchy ZeBobo5 [C#] MDI child et MDI parent : Laison [ par MickParadiseLost ] Bonjour a tous, J'ai une barre d'outils dans ma forme principale et elle contient un pinceau et une gomme. J'aimerai pouvoir peindre avec mon pinceau [C#] MDI: passage de paramêtres [ par MickParadiseLost ] Bonne nuit a tous, J'aimerais connaitre la méthode la plus simple pour pouvoir dessiner dans ma fenetre MDI child lorsque je clique sur un bouton problème pour réactiver mon menu [ par ratsimisampy ] voici mon problème: jai deux form, parent et child jouvre mon child grace a un menu que je rend inactif lorsque je ferme mon child, je voudrai


Nos sponsors

Sondage...

CalendriCode

Octobre 2008
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel BAÏSE, 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,374 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é.