Comment effectuer une copie profonde d'un objet non marqué comme sérialisable (en C #)?

J'essaye de créer une pile de Presse-papiers en C #. Les données du Presse-papiers sont stockées dans des objets System.Windows.Forms.DataObject . Je voulais stocker chaque entrée de presse-papiers ( IDataObject ) directement dans une liste générique. En raison de la façon dont les bitmaps (semblent être) stockés, je pense que je dois d'abord effectuer une copie profonde avant de l'ajouter à la liste.

J'ai essayé d'utiliser la sérialisation binaire (voir ci-dessous) pour créer une copie profonde, mais comme System.Windows.Forms.DataObject n'est pas marqué comme sérialisable, l'étape de sérialisation échoue. Des idées?

public IDataObject GetClipboardData()
{
    MemoryStream memoryStream = new MemoryStream();
    BinaryFormatter binaryFormatter = new BinaryFormatter();
    binaryFormatter.Serialize(memoryStream, Clipboard.GetDataObject());
    memoryStream.Position = 0;
    return (IDataObject) binaryFormatter.Deserialize(memoryStream);
}
3

3 Réponses

J'ai écrit le code ci-dessous pour une autre question et peut-être que cela pourrait vous être utile dans ce scénario:

    public static class GhettoSerializer
    {
           //you could make this a factory method if your type
           //has a constructor that appeals to you (i.e. default 
           //parameterless constructor)
            public static void Initialize(T instance, IDictionary values)
            {
                    var props = typeof(T).GetProperties();

                   //my approach does nothing to handle rare properties with array indexers
                    var matches = props.Join(
                            values,
                            pi => pi.Name,
                            kvp => kvp.Key,
                            (property, kvp) =>
                                    new {
                                            Set = new Action(property.SetValue), 
                                            kvp.Value
                                    }
                    );

                    foreach (var match in matches)
                            match.Set(instance, match.Value, null);
            }
            public static IDictionary Serialize(T instance) { var props = typeof(T).GetProperties(); var ret = new Dictionary(); foreach (var property in props) { if (!property.CanWrite || !property.CanRead) continue; ret.Add(property.Name, property.GetValue(instance, null)); } return ret; } } 

Cependant, je ne pense pas que ce sera la solution finale à votre problème, même si cela peut vous donner une place pour commencer.

3
ajouté
Oui, c'est un bug dans le code. Au lieu de typeof (T) .GetProperties() , il faut dire instance.GetType (). GetProperties() . En fait, je dirais qu'il devrait utiliser les champs plutôt que les propriétés, mais c'est un choix de conception.
ajouté l'auteur Timwi, source
Merci d'avoir pris une photo (points pour la convention de nommage de classe aussi). Malheureusement IDataObject ne contient aucune propriété. Les données sont "extraites" à l'aide de méthodes, de sorte que le code ci-dessus renvoie un dictionnaire vide.
ajouté l'auteur cgray4, source

Copy of my answer to: difference between DataContract attribute and Serializable attribute in .net

Ma réponse correspond beaucoup mieux ici que là, bien que la question ci-dessus se termine par:

"... ou peut-être une façon différente de créer un deepclone?"

Une fois, j'ai effectué une inspection sur une structure d'objet via Reflection pour trouver tous les assemblages requis pour la désérialisation et les sérialiser pour le bootstrapping.

Avec un peu de travail, on pourrait construire une méthode similaire pour la copie en profondeur. Fondamentalement, vous avez besoin d'une méthode récursive qui se déplace le long d'un dictionnaire pour détecter les références circulaires. Dans la méthode, vous inspectez tous les champs comme ceci:

private void InspectRecursively(object input,
    Dictionary processedObjects)
{
  if ((input != null) && !processedObjects.ContainsKey(input))
  {
    processedObjects.Add(input, true);

    List fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); foreach (FieldInfo field in fields) { object nextInput = field.GetValue(input); if (nextInput is System.Collections.IEnumerable) { System.Collections.IEnumerator enumerator = (nextInput as System.Collections.IEnumerable).GetEnumerator(); while (enumerator.MoveNext()) { InspectRecursively(enumerator.Current, processedObjects); } } else { InspectRecursively(nextInput, processedObjects); } } } } 

To get it working you need to add an output object and something like System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type) to create the most shallowest copy (even without copying references) of each field's value. Finally you can set each field with something like field.SetValue(input, output)

Toutefois, cette implémentation ne prend pas en charge les gestionnaires d'événements enregistrés, ce qui est _ un _ pris en charge par la désérialisation. De plus, chaque objet de la hiérarchie sera rompu si le constructeur de sa classe a besoin d'initialiser autre chose que de définir tous les champs. Le dernier point ne fonctionne qu'avec la sérialisation, si la classe a une implémentation respective, par ex. méthode marquée [OnDeserialized] , implémente ISerializable , ....

0
ajouté

Rechercher les docks pour Serializable et trouver les choses sur les aides de sérialisation. Vous pouvez envelopper le bitmap dans votre propre code de sérialisation qui s'intègre au framework .net.

0
ajouté