Permalänk
Medlem

Serializera i C#

Jag har en klass som ärver ISerializable(C#). Mitt problem är att jag vill att ett program som serializera och ett ska deserializera. Men det verkar inte gå, utan det funkar enbart när de ligger i samma projekt vilket är lite jobbigt. Hur kommer man runt det?

Visa signatur

Real Programmers always confuse Christmas and Halloween because OCT 31 == DEC 25 !

Permalänk

lägg klassen som du ska serialisera i ett eget projekt som blir en dll-fil.
sen kan du ta med den dll-filen som referens i alla andra projekt som ska kunna serialisera och deserailisera den klassen.

Permalänk
Medlem

Jag gjorde en litet exempel du kan titta på.

Visa signatur
Permalänk
Medlem

Att via referens är alltid att föredra som det föreslogs ovan, men då man inte har tillgång till assemblen (.dll el. .exe) så kan man ange en SerializationBinder till din *Formatter klass.

Då behöver programmet som deserialiserar enbart veta vad de olika fälten heter och dess typ. (i detta exempel iaf)

Lite långt men jag postar de två 'projekten' iaf.

Först programmet för att serialisera en klass med ISerializable interfacet.

using System; using System.Runtime.Serialization; using System.Collections.Generic; using System.Security.Permissions; using System.IO; using System.Runtime.Serialization.Formatters.Binary; /// C# / NET 2.0 / AUTOGENERATED 24 jul 2006 namespace Zoomware.Examples.Serialization { // this program serialize data to test.dat class TestClassA { [STAThread] static void Main ( string [ ] args ) { MyCustomSerializableClassA classA = new MyCustomSerializableClassA ( ); classA.n = 456; try { using ( FileStream stream = new FileStream ( @d:\test.dat, FileMode.Create ) ) { BinaryFormatter formatter = new BinaryFormatter ( ); formatter.Serialize ( stream, classA ); } } catch ( SerializationException e ) { Console.WriteLine ( e.Message ); } } } [Serializable] public class MyCustomSerializableClassA : ISerializable { public MyCustomSerializableClassA ( ) { } protected MyCustomSerializableClassA ( SerializationInfo info, StreamingContext context ) { n = info.GetInt32 ( "myint" ); s = info.GetString ( "mystring" ); } [SecurityPermissionAttribute ( SecurityAction.Demand, SerializationFormatter = true )] public void GetObjectData ( SerializationInfo info, StreamingContext context ) { info.AddValue ( "myint", n ); info.AddValue ( "mystring", s ); } public int n = 123; private string s = "abc"; } }

Och, sedan deserialiseringen med användandet av en egen SerializationBinder.

using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Security.Permissions; using System.IO; using System.Runtime.Serialization.Formatters.Binary; /// C# / NET 2.0 / AUTOGENERATED 24 jul 2006 namespace Zoomware.Examples.Serialization { // this program deserialize data from test.dat without knowing the base class it was serialized from class TestClassB { [STAThread] static void Main ( string [ ] args ) { try { using ( FileStream stream = new FileStream ( @d:\test.dat, FileMode.Open ) ) { BinaryFormatter formatter = new BinaryFormatter ( ); formatter.Binder = new TypeAToTypeB ( ); MyCustomSerializableClassB classB = new MyCustomSerializableClassB ( ); Console.WriteLine ( "new class B: {0}, {1}", classB.n, classB.s ); classB = ( MyCustomSerializableClassB ) formatter.Deserialize ( stream ); Console.WriteLine ( "deserialized class B: {0}, {1}", classB.n, classB.s ); } } catch ( Exception e ) { Console.WriteLine ( e.Message ); } } } [Serializable] public class MyCustomSerializableClassB : ISerializable { public MyCustomSerializableClassB ( ) { } protected MyCustomSerializableClassB ( SerializationInfo info, StreamingContext context ) { n = info.GetInt32 ( "myint" ); s = info.GetString ( "mystring" ); } [SecurityPermissionAttribute ( SecurityAction.Demand, SerializationFormatter = true )] public void GetObjectData ( SerializationInfo info, StreamingContext context ) { info.AddValue ( "myint", n ); info.AddValue ( "mystring", s ); } public int n = 0; public string s = string.Empty; public string s2 = "another string that does not exists in the other class so there is an obvious difference"; } public class TypeAToTypeB : System.Runtime.Serialization.SerializationBinder { public override Type BindToType ( string assemblyName, string typeName ) { return typeof ( MyCustomSerializableClassB ); } } }

EDIT: fixade return raden i BindToType så att den använde typeof på ett bättre sätt.

Permalänk
Medlem

Problemet med en binder blir att jag vill kunna (detta ska användas för att skicka object över sockets) skicka många olika typer av objekt.

När jag provar att lägga klasserna i en dll så står det, när jag försöker deserializera, att den inte kan hitta vissa members, trots att jag är helt säker på att jag lagt till dom i GetObjectData-metoden.

Visa signatur

Real Programmers always confuse Christmas and Halloween because OCT 31 == DEC 25 !

Permalänk
Medlem

Ett enkelt sätt ska väl vara att med info.MemberCount se hur många objekt som finns i filen. Jämför MemberCount efter serialiseringen och före deserialiseringen i respektive program.

Permalänk
Medlem

Jag var bara lite dum i huvudet, det är fixat nu.

Visa signatur

Real Programmers always confuse Christmas and Halloween because OCT 31 == DEC 25 !