Serialization problem
-
I'm having a hard time deserializing old versions of a class after adding a new member. I've written a toy program that's the simplest possible example of this problem. Maybe someone else might notice what I'm doing wrong. I have a class with one member: A System.Drawing.Color:
\[Serializable\] public class SerialObj { public System.Drawing.Color color; }
The following code serializes/deserializes it with no problem:
SoapFormatter formatter = new SoapFormatter(); // Serialize: formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; formatter.Serialize(myStream, so); SoapFormatter formatter = new SoapFormatter(); // Deserialize: formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; so = (SerialObj)formatter.Deserialize(myStream);
I added an int member, and I'm trying to use the ISerializable interface to handle the different versions. This interface requires a constructor with two special parameters, and a GetObjectData method:
\[Serializable\] public class SerialObj : ISerializable { public System.Drawing.Color color; public int number; // The new member. public SerialObj() { System.Windows.Forms.MessageBox.Show("In empty ctor."); } public SerialObj(SerializationInfo info, StreamingContext cntxt) { System.Windows.Forms.MessageBox.Show("In full ctor."); color = (System.Drawing.Color)info.GetValue("color", typeof(System.Drawing.Color)); try { number = info.GetInt32("number"); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } } void ISerializable.GetObjectData(SerializationInfo inf, StreamingContext cxt) { System.Windows.Forms.MessageBox.Show("In GetObjectData."); inf.AddValue("color", color); inf.AddValue("number", number); } }
It works for serialized new versions with both members. But when I deserialize an old version (without the int), it crashes on the Deserialize call, with the exception: "Top Object cannot be instantiated for element 'color'." It never even calls either constructor. Can
-
I'm having a hard time deserializing old versions of a class after adding a new member. I've written a toy program that's the simplest possible example of this problem. Maybe someone else might notice what I'm doing wrong. I have a class with one member: A System.Drawing.Color:
\[Serializable\] public class SerialObj { public System.Drawing.Color color; }
The following code serializes/deserializes it with no problem:
SoapFormatter formatter = new SoapFormatter(); // Serialize: formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; formatter.Serialize(myStream, so); SoapFormatter formatter = new SoapFormatter(); // Deserialize: formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; so = (SerialObj)formatter.Deserialize(myStream);
I added an int member, and I'm trying to use the ISerializable interface to handle the different versions. This interface requires a constructor with two special parameters, and a GetObjectData method:
\[Serializable\] public class SerialObj : ISerializable { public System.Drawing.Color color; public int number; // The new member. public SerialObj() { System.Windows.Forms.MessageBox.Show("In empty ctor."); } public SerialObj(SerializationInfo info, StreamingContext cntxt) { System.Windows.Forms.MessageBox.Show("In full ctor."); color = (System.Drawing.Color)info.GetValue("color", typeof(System.Drawing.Color)); try { number = info.GetInt32("number"); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } } void ISerializable.GetObjectData(SerializationInfo inf, StreamingContext cxt) { System.Windows.Forms.MessageBox.Show("In GetObjectData."); inf.AddValue("color", color); inf.AddValue("number", number); } }
It works for serialized new versions with both members. But when I deserialize an old version (without the int), it crashes on the Deserialize call, with the exception: "Top Object cannot be instantiated for element 'color'." It never even calls either constructor. Can
Try this.... // Version 1.0 [Serializable] public class SerialObj { public System.Drawing.Color color; } // Version 2.0 [Serializable] public class SerialObj { public System.Drawing.Color color; [OptionalField(VersionAdded = 2)] public int number; } // Version 3.0 [Serializable] public class SerialObj { public System.Drawing.Color color; [OptionalField(VersionAdded=2)] public int number; [OptionalField(VersionAdded=3)] public int solution; }
-
Try this.... // Version 1.0 [Serializable] public class SerialObj { public System.Drawing.Color color; } // Version 2.0 [Serializable] public class SerialObj { public System.Drawing.Color color; [OptionalField(VersionAdded = 2)] public int number; } // Version 3.0 [Serializable] public class SerialObj { public System.Drawing.Color color; [OptionalField(VersionAdded=2)] public int number; [OptionalField(VersionAdded=3)] public int solution; }
Thanks for the suggestion, but according to this (http://msdn.microsoft.com/en-us/library/ms229752.aspx[^]) the OptionalField attribute doesn't work with the SoapFormatter (just the BinaryFormatter). Versions have been released using the SoapFormatter, so I can't change it at this point.
-
I'm having a hard time deserializing old versions of a class after adding a new member. I've written a toy program that's the simplest possible example of this problem. Maybe someone else might notice what I'm doing wrong. I have a class with one member: A System.Drawing.Color:
\[Serializable\] public class SerialObj { public System.Drawing.Color color; }
The following code serializes/deserializes it with no problem:
SoapFormatter formatter = new SoapFormatter(); // Serialize: formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; formatter.Serialize(myStream, so); SoapFormatter formatter = new SoapFormatter(); // Deserialize: formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; so = (SerialObj)formatter.Deserialize(myStream);
I added an int member, and I'm trying to use the ISerializable interface to handle the different versions. This interface requires a constructor with two special parameters, and a GetObjectData method:
\[Serializable\] public class SerialObj : ISerializable { public System.Drawing.Color color; public int number; // The new member. public SerialObj() { System.Windows.Forms.MessageBox.Show("In empty ctor."); } public SerialObj(SerializationInfo info, StreamingContext cntxt) { System.Windows.Forms.MessageBox.Show("In full ctor."); color = (System.Drawing.Color)info.GetValue("color", typeof(System.Drawing.Color)); try { number = info.GetInt32("number"); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } } void ISerializable.GetObjectData(SerializationInfo inf, StreamingContext cxt) { System.Windows.Forms.MessageBox.Show("In GetObjectData."); inf.AddValue("color", color); inf.AddValue("number", number); } }
It works for serialized new versions with both members. But when I deserialize an old version (without the int), it crashes on the Deserialize call, with the exception: "Top Object cannot be instantiated for element 'color'." It never even calls either constructor. Can
Hi Alan, I haven't studied the subject yet, however it so happens I just read a CP thread about this, and it seems you need to use SerializationBinder class. MSDN even holds an example. :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
-
Hi Alan, I haven't studied the subject yet, however it so happens I just read a CP thread about this, and it seems you need to use SerializationBinder class. MSDN even holds an example. :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
Thanks Luc. I have tried using a custom SerializationBinder (for the formatter.Binder member). It implements a single method, BindToType, which appears to be used repeatedly as a subroutine for the .NET framework serialization, that returns a Type when given a typeName string. It didn't avoid the error message I'm getting. The error happens after the return from the Binder, with the type that had the added member.
-
Try this.... // Version 1.0 [Serializable] public class SerialObj { public System.Drawing.Color color; } // Version 2.0 [Serializable] public class SerialObj { public System.Drawing.Color color; [OptionalField(VersionAdded = 2)] public int number; } // Version 3.0 [Serializable] public class SerialObj { public System.Drawing.Color color; [OptionalField(VersionAdded=2)] public int number; [OptionalField(VersionAdded=3)] public int solution; }
Migounette, I tried your suggestion anyway, and it works with the new versions (both members), but not with the old versions (color member only). The error message is: "Member at position 0 was null. Parameter name: members". I don't have any variable named "members", so it must be referring to something internal to .NET.
-
Migounette, I tried your suggestion anyway, and it works with the new versions (both members), but not with the old versions (color member only). The error message is: "Member at position 0 was null. Parameter name: members". I don't have any variable named "members", so it must be referring to something internal to .NET.
Not sure about the error Members of what ? Try this: public int number { get; set; } or I was looking at SOAP (never played with), but maybe with the extension of the attribute for soap envelop may work. http://msdn.microsoft.com/en-us/library/system.xml.serialization.soapignoreattribute.aspx[^] Good luck :)