Cum se efectuează o copie profundă a unui obiect care nu este marcat ca serializabil (în C #)?

Încerc să creez o stivă de Clipboard în C #. Datele din Clipboard sunt stocate în obiecte System.Windows.Forms.DataObject . Am vrut să stochez fiecare intrare clipboard ( IDataObject ) direct într-o listă generică. Din cauza modului în care sunt stocate Bitmap-urile (par a fi), mă gândesc că trebuie să fac o copie profundă înainte să o adaug pe listă.

Am încercat să folosesc serializarea binară (a se vedea mai jos) pentru a crea o copie profundă, dar deoarece System.Windows.Forms.DataObject nu este marcată ca serializabilă, etapa de serializare nu reușește. Vreo idee?

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ăspunsuri

Am scris codul de mai jos pentru o altă întrebare și poate că ar putea fi util pentru dvs. în acest scenariu:

    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;
            }
    }

Cu toate acestea, nu cred că aceasta va fi soluția finală a problemei dvs., deși vă poate oferi un loc pentru a începe.

3
adăugat
Da, este un bug în cod. În loc de typeof (T) .GetProperties() , ar trebui să spună instance.GetType (). GetProperties() . De fapt, aș susține că ar trebui să folosească de fapt câmpurile, mai degrabă decât proprietățile, dar aceasta este o alegere de design.
adăugat autor Timwi, sursa
Vă mulțumim că ați făcut o lovitură la acest punct (și pentru convențiile de numire în clasă). Din păcate, IDataObject nu conține proprietăți. Datele sunt "extrase" folosind metode, astfel încât codul de mai sus returnează un Dicționar gol.
adăugat autor cgray4, sursa

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

Răspunsul meu se potrivește mult mai bine aici decât acolo, deși întrebarea de mai sus se încheie cu:

"... sau poate o altă modalitate de a crea o clonă profundă?"

Am efectuat o dată o inspecție la o structură obiect prin Reflection pentru a găsi toate ansamblurile necesare pentru deserializare și pentru a le serializa alături de bootstrapping.

Cu un pic de lucru s-ar putea construi o metodă similară pentru copierea profundă. Practic aveți nevoie de o metodă recursivă care să transporte un Dicționar pentru a detecta referințele circulare. În interiorul metodei inspectați toate câmpurile despre aceasta:

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)

Cu toate acestea, această implementare nu suportă gestionarea evenimentului înregistrat, care este _ un _supported și de deserializarea. În plus, fiecare obiect din ierarhie va fi rupt, în cazul în care constructorul său de clasă trebuie să inițializeze orice, dar să stabilească toate câmpurile. Ultimul punct funcționează numai cu serializare, dacă clasa are o implementare respectivă, de ex. metoda marcată [OnDeserialized] , implementează ISerializable , ....

0
adăugat

Căutați docurile pentru Serializabil și găsiți chestii despre ajutoarele de serializare. Puteți împacheta bitmap-ul în propriul cod de serializare integrat cu cadrul .net.

0
adăugat