/// <summary>
        /// Réalise une copie profonde de l'objet
        /// </summary>
        /// <param name="originalObject">Objet original à copier</param>
        /// <param name="visited">Liste des propriétés et valeurs déjà copiées</param>
        /// <returns>Object copier</returns>
        private static Object InternalCopy(Object originalObject, IDictionary <Object, Object> visited)
        {
            //Si on recoit null on ne fait pas de copie
            if (originalObject == null)
            {
                return(null);
            }

            //Récupératino du type de l'objet
            var typeToReflect = originalObject.GetType();

            //Si c'est un type primitif on peut directement le renvoyer car il est passé en copie et non en référence
            if (PrimitiveTypesHelper.IsPrimitive(typeToReflect))
            {
                return(originalObject);
            }

            //Si on a déjà fait la copie on ne va pas la refaire alors on renvoi la copie effectuée
            if (visited.ContainsKey(originalObject))
            {
                return(visited[originalObject]);
            }

            //SI c'est un délégué et qu'on ne peut pas lui assigner notre type on renvoi null
            if (typeof(Delegate).IsAssignableFrom(typeToReflect))
            {
                return(null);
            }

            //Appel de la méthode du framework pour copier les propriétés simples de l'objet
            var cloneObject = CloneMethod.Invoke(originalObject, null);

            //Si mon objet est un tableau
            if (typeToReflect.IsArray)
            {
                //Récupération du type des élements contenus dedans
                var arrayType = typeToReflect.GetElementType();
                if (!PrimitiveTypesHelper.IsPrimitive(arrayType))
                {
                    Array clonedArray = (Array)cloneObject;
                    for (int i = 0; i < clonedArray.Length; i++)
                    {
                        clonedArray.SetValue(InternalCopy(clonedArray.GetValue(i), visited), i);
                    }
                    //Array clonedArray = (Array)cloneObject;
                    //clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices));
                }
            }
            //Ajout de l'objet actuel dans la liste des visités
            visited.Add(originalObject, cloneObject);

            //Copie de tous les champs du type
            CopyFields(originalObject, visited, cloneObject, typeToReflect);

            RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect);
            return(cloneObject);
        }
 /// <summary>
 /// Réalise la copie des champs pour l'objet
 /// </summary>
 /// <param name="originalObject">Objet dont on copie les champs</param>
 /// <param name="visited">Liste des objets visités</param>
 /// <param name="cloneObject">Objet cloné</param>
 /// <param name="typeToReflect">Type sur lequel on se trouve</param>
 /// <param name="bindingFlags">Informations sur le type du champs</param>
 /// <param name="filter">Filtre à effectuer sur les propriétés</param>
 private static void CopyFields(object originalObject, IDictionary <object, object> visited, object cloneObject, Type typeToReflect, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy, Func <FieldInfo, bool> filter = null)
 {
     //parcours des propriétés du type
     foreach (FieldInfo fieldInfo in typeToReflect.GetFields(bindingFlags))
     {
         if ((filter == null || !filter(fieldInfo)) && PrimitiveTypesHelper.IsPrimitive(fieldInfo.FieldType))
         {
             var originalFieldValue = fieldInfo.GetValue(originalObject);
             var clonedFieldValue   = InternalCopy(originalFieldValue, visited);
             fieldInfo.SetValue(cloneObject, clonedFieldValue);
         }
     }
 }