Avatar billede mcbyte Nybegynder
20. juni 2005 - 18:11 Der er 22 kommentarer og
1 løsning

Serialisering af objekter som ikke er markeret med [Serializable]

Tjah, opgaven kan egetlig defineres ganske enkelt, ligesom angivet i spørgsmålets titel.

Jeg skal bruge en metode, wrapper-klasse eller noget andet som kan tage et serialisere et objekt som ikke er markeret med [Serializable]

Helt specifikt skal jeg bruge det til at serialisere f.eks. et Microsoft.Office.Interop.Outlook.AppointmentItem.
Hvis jeg prøver at serialisere et objekt indeholdene et sådanne objekt, eller hvilket som helst andet objekt som ikke er markeret med [Serializable], kaster den om sig med undtagelser - f.eks.: "ReadCallback Exception: System.Runtime.Serialization.SerializationException: Type 'System.__ComObject' in Assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable."

Er der nogen som kan klare denne opgave - i så fald vil det være MEGET værdsat.

Med venlig hilsen
Thomas René Sidor
Avatar billede arne_v Ekspert
20. juni 2005 - 18:20 #1
du vil serialisere noget som ikke er serialiserbart ?
Avatar billede mcbyte Nybegynder
20. juni 2005 - 18:36 #2
Ja, sådan kan man også udtrykke det :)

Jeg har set det gjort i Java - men er det overhovedet muligt i C# / .Net?
Avatar billede arne_v Ekspert
20. juni 2005 - 18:56 #3
du kan vel heller ikke serialisere noget i Java som ikke implementerer
java.io.Serializable, men der er nogle alternativer for klasser som
opfylder java beans konventionen, er det dem som du tænker på ?
Avatar billede mcbyte Nybegynder
20. juni 2005 - 19:09 #4
Avatar billede arne_v Ekspert
20. juni 2005 - 19:23 #5
ah - nu er jeg med

ja - jeg tror godt at du kan lave samme nummer i .NET

transient => [NonSerialized]

writeObject & readObject metoder => ISerializable interface og en GetObjectData metode og en speciel constructor

men husk at det kun læser problemet hvis både ind og ud bruger den samme adapter - eller
sagt på en anden måde - det virker kun hvis end koden både ind og ud er under din kontrol
Avatar billede mcbyte Nybegynder
20. juni 2005 - 19:54 #6
Jeg har adgang til det hele, så hvis du kan et lidt mere uddybende eksempel, så er jeg glad! :)
Avatar billede arne_v Ekspert
20. juni 2005 - 19:56 #7
jeg prøvet at brygge noget sammen
Avatar billede arne_v Ekspert
20. juni 2005 - 20:53 #8
først den java version jeg tog udgangspunkt i:

package ser;

import java.io.Serializable;

public class SerializableAdapter implements Serializable {
    protected transient Object object;

    public Object getObject() {
        return object;
    }
}

package ser;

public class Data {
    private int iv;

    private String sv;

    public int getIv() {
        return iv;
    }

    public void setIv(int iv) {
        this.iv = iv;
    }

    public String getSv() {
        return sv;
    }

    public void setSv(String sv) {
        this.sv = sv;
    }

    public String toString() {
        return ("[" + iv + ":" + sv + "]");
    }
}

package ser;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {
    private static byte[] serialize(Object o) throws IOException {
        ByteArrayOutputStream ba = new ByteArrayOutputStream(1000);
        ObjectOutputStream oba = new ObjectOutputStream(ba);
        oba.writeObject(o);
        return ba.toByteArray();
    }

    private static Object deserialize(byte[] b) throws IOException, ClassNotFoundException {
        ByteArrayInputStream ba = new ByteArrayInputStream(b);
        ObjectInputStream oba = new ObjectInputStream(ba);
        return oba.readObject();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Data o = new Data();
        o.setIv(123);
        o.setSv("abc");
        System.out.println(o);
        byte[] b = serialize(new DataSerializable(o));
        Data o2 = (Data) ((SerializableAdapter)deserialize(b)).getObject();
        System.out.println(o2);
    }
}

class DataSerializable extends SerializableAdapter {
    public DataSerializable(Data o) {
        object = o;
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.writeInt(((Data)object).getIv());
        oos.writeUTF(((Data)object).getSv());
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        object = new Data();
        ((Data)object).setIv(ois.readInt());
        ((Data)object).setSv(ois.readUTF());
    }

}

og så den tilsvarende C# version:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Ser
{
    abstract public class SerializableAdapter : ISerializable
    {
        [NonSerialized]
        protected object obj;
        abstract public void GetObjectData(SerializationInfo info, StreamingContext context);
        public object Obj
        {
            get
            {
                return obj;
            }
        }
    }
    public class Data
    {
        private int iv;
        private String sv;
        public int Iv
        {
            get
            {
                return iv;
            }
            set
            {
                iv = value;
            }
        }
        public string Sv
        {
            get
            {
                return sv;
            }
            set
            {
                sv = value;
            }
        }
        public override string ToString()
        {
            return ("[" + iv + ":" + sv + "]");
        }
    }
    [Serializable]
    class DataSerializable : SerializableAdapter
    {
        public DataSerializable(Data o)
        {
            obj = o;
        }
        private DataSerializable(SerializationInfo info, StreamingContext context)
        {
            obj = new Data();
            ((Data)obj).Iv =  info.GetInt32("iv");
            ((Data)obj).Sv =  info.GetString("sv");
        }
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("iv", ((Data)obj).Iv);
            info.AddValue("sv", ((Data)obj).Sv);
        }
    }
    class Test
    {
        public static byte[] Serialize(Object o)
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, o);
            return ms.ToArray();
        }
        public static object Deserialize(byte[] b)
        {
            MemoryStream ms = new MemoryStream(b);
            BinaryFormatter bf = new BinaryFormatter();
            ms.Position = 0;
            return bf.Deserialize(ms);
        }
        public static void Main(string[] args)
        {
            Data o = new Data();
            o.Iv = 123;
            o.Sv = "abc";
            Console.WriteLine(o);
            byte[] b = Serialize(new DataSerializable(o));
            Data o2 = (Data)((DataSerializable)Deserialize(b)).Obj;
            Console.WriteLine(o2);
        }
    }
}
Avatar billede mcbyte Nybegynder
20. juni 2005 - 21:31 #9
Jeg må sige at det er et flot stykke arbejde, men desværre virker det umiddelbart ikke for mig eftersom at den klasse jeg ønsker at serialisere ikke er en klasse jeg selv har konstrueret, og selv ved at prøve at ændre DataSerializable til at være lidt mere generel får jeg stadig min exception fra tidligere. Problemet ligger nok i at den prøver at serialisere den kæde af objekter som der er i klassen.

      [Serializable]
class DataSerializable : SerializableAdapter
{
    public DataSerializable(Data o)
    {
        obj = o;
    }
    private DataSerializable(SerializationInfo info, StreamingContext context)
    {
        obj = new Data();
        ((Data)obj).Iv = info.GetValue("iv",typeof(Data));
    }
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("iv",((Data)obj).Iv,typeof(Data));
    }
}

Umiddelbart tror jeg ikke at det kan lade sig gøre overhovedet.
Avatar billede arne_v Ekspert
20. juni 2005 - 21:45 #10
der er ikke noget i min kode som gør at man behøver selv behøver at have lavet Data
eller at den kan noget specielt (bortset fra at man kan sætte dens værdier)

men hvis Data selv indeholder nogle objekter som ikke er kan det godt blive
tricky

men det burde vel kunne lade sig gøre at pille alle de atomiske dele
ud når der skal serialiseres og samle dem igen når der skal deserialiseres

metoderne bliver noget større end de iv & sv eksempler men bør det ikke
kunne lade sig gøre ?
Avatar billede mcbyte Nybegynder
20. juni 2005 - 22:55 #11
Jo, umiddelbart ville det nok kunne lade sig gøre - men pointen var at jeg gerne ville være fri for at skulle skrive så meget. En generel wrapper er nu engang pænere.

Jeg tror dog at det ender med at jeg blot skriver en data container som er seriliserbar - noget besværligt med alle de attributter der er i de oprindelige objekter. Så hellere bruge en dag eller to på at skrive en generel serializer ;)
Avatar billede arne_v Ekspert
20. juni 2005 - 23:42 #12
du kunne jo lave en  DataSerializable som brugte reflection til f.eks. at løbe
gennem alle properties

det skulle ikke være så svært
Avatar billede mcbyte Nybegynder
21. juni 2005 - 18:25 #13
Reflection? Det har jeg umiddelbart ikke hørt om - kan du give et kort eksempel?
Avatar billede arne_v Ekspert
21. juni 2005 - 19:46 #14
jeg prøver
Avatar billede arne_v Ekspert
21. juni 2005 - 20:54 #15
jeg har implementeret reflection og reorganiseret lidt i koden

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;

namespace Ser
{
    [Serializable]
    public class GeneralSerializableAdapter : ISerializable
    {
        [NonSerialized]
        private object obj;
        public GeneralSerializableAdapter(Object o)
        {
            obj = o;
        }
        private GeneralSerializableAdapter(SerializationInfo info, StreamingContext context)
        {
            obj = Assembly.GetExecutingAssembly().CreateInstance(info.GetString("class"));
            PropertyInfo[] allp = obj.GetType().GetProperties();
            foreach(PropertyInfo p in allp)
            {
                if(p.PropertyType == typeof(int))
                {
                    p.SetValue(obj, info.GetInt32(p.Name), null);
                }
                else if(p.PropertyType == typeof(double))
                {
                    p.SetValue(obj, info.GetDouble(p.Name), null);
                }
                else if(p.PropertyType == typeof(string))
                {
                    p.SetValue(obj, info.GetString(p.Name), null);
                }
                else
                {
                    // ignore for now
                }
            }
        }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("class", obj.GetType().FullName);
            PropertyInfo[] allp = obj.GetType().GetProperties();
            foreach(PropertyInfo p in allp)
            {
                info.AddValue(p.Name, p.GetValue(obj, null));
            }
        }
        public object Obj
        {
            get
            {
                return obj;
            }
        }
    }
    public class Data
    {
        private int iv;
        private String sv;
        public int Iv
        {
            get
            {
                return iv;
            }
            set
            {
                iv = value;
            }
        }
        public string Sv
        {
            get
            {
                return sv;
            }
            set
            {
                sv = value;
            }
        }
        public override string ToString()
        {
            return ("[" + iv + ":" + sv + "]");
        }
    }
    public class Data2
    {
        private String sv;
        private double xv;
        public string Sv
        {
            get
            {
                return sv;
            }
            set
            {
                sv = value;
            }
        }
        public double Xv
        {
            get
            {
                return xv;
            }
            set
            {
                xv = value;
            }
        }
        public override string ToString()
        {
            return ("[" + sv + ":" + xv + "]");
        }
    }
    class Test
    {
        public static byte[] Serialize(Object o)
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, new GeneralSerializableAdapter(o));
            return ms.ToArray();
        }
        public static object Deserialize(byte[] b)
        {
            MemoryStream ms = new MemoryStream(b);
            BinaryFormatter bf = new BinaryFormatter();
            ms.Position = 0;
            return ((GeneralSerializableAdapter)bf.Deserialize(ms)).Obj;
        }
        public static void Main(string[] args)
        {
            Data o = new Data();
            o.Iv = 123;
            o.Sv = "abc";
            Console.WriteLine(o);
            byte[] b = Serialize(o);
            Data ox = (Data)Deserialize(b);
            Console.WriteLine(ox);
            Data2 o2 = new Data2();
            o2.Sv = "xyz";
            o2.Xv = 123.456;
            Console.WriteLine(o2);
            byte[] b2 = Serialize(o2);
            Data2 o2x = (Data2)Deserialize(b2);
            Console.WriteLine(o2x);
        }
    }
}
Avatar billede arne_v Ekspert
21. juni 2005 - 20:55 #16
den er ikke færdig - den håndterer kun properties og kun int + double + string, men
teknikken skulle være illustreret
Avatar billede arne_v Ekspert
23. juni 2005 - 15:15 #17
??
Avatar billede mcbyte Nybegynder
23. juni 2005 - 20:06 #18
Så, havde lige en eksamen der skulle overstås. Men jeg takker mange gange for hjælpen. Det lykkedes mig ikke at bruge din hjælp til det det oprindeligt var tiltænkt, men til et andet projekt. Den første problemstilling fik jeg løst på andne vis.

Men mange tak for hjælpen :)
Avatar billede mcbyte Nybegynder
23. juni 2005 - 20:06 #19
Hvis du smider et svar, så godkender jeg det... :)
Avatar billede arne_v Ekspert
23. juni 2005 - 20:07 #20
ok
Avatar billede arne_v Ekspert
24. juli 2005 - 15:57 #21
så mangler du bare at accptere det
Avatar billede mcbyte Nybegynder
26. juli 2005 - 15:01 #22
Ah, mente bestemt jeg havde gjort det. Men jeg havde ikke lige gennemskuet at jeg skulle markere dig i listen før den accepterer.
Avatar billede arne_v Ekspert
26. juli 2005 - 15:09 #23
det er en lille finesse på Eksperten som ofte driller folk, fordi den er lidt ulogisk
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester