John said:
As shown in the sample code. The class is inherited from
CollectionBase. Since I found the collectionBase cannot
deserilize its List correctly. I found a work around using
array to ser/deserialize the elements. After I get the
array out using .GetValue, I can put them in the List.
But now, the class' constructor will not be invoked
in .GetValue, when I call List.Add(), List complains I am
trying to add in null value.
Because the old version was ship a year ago, I have to
maintain the backward compatability.
I found a work around, though not a pretty one. I keep a
class array to hold the deserilzing result and keep the
List empty. Filling the List from the class array will be
trigger by any attemping to access the List operation such
as .Count, [index] and so on.
Any suggestions?
Yes - you want to also inherit from IDeserializationCallback. The
method defined by this interface will be called once all of the objects
have been deserialized.
I'd also suggest putting the reference to the deserialized array in a
private instance member rather than a class array (I assume you mean
static?). When OnDeserialization() is called, you can walk the array
and call List.Add() with those objects - they are fully deserialized at
that point.
See a modified version of your sample at the end of this post for details.
I was confused at first when running your sample in framework 1.0,
because the PText objects were not deserialized when you added them back
into the list (the Text property was always the empty string). but in
framework 1.1, the Text property is null instead of the empty string, so
List.Add() complains.
//====== Sample implementing IDeserializationCallback ====
using System;
using System.Collections;
using System.Data;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinarySerialization {
/// <summary>
/// Summary description for Class1.
/// </summary>
class Test {
static private MemoryStream mstream = new MemoryStream();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) {
//
// TODO: Add code to start application here
//
Ser();
DeSer();
}
static void Ser() {
P _p = new P();
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(mstream, _p);
mstream.Seek( 0, SeekOrigin.Begin);
}
static void DeSer() {
mstream.Seek( 0, SeekOrigin.Begin);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Binder = new MyBinder();
P _p = (P)bformatter.Deserialize( mstream);
mstream.Seek( 0, SeekOrigin.Begin);
// show that the deserialization worked
foreach (PText ptext in _p) {
Console.WriteLine( "Text is \"{0}\"", ptext.Text);
}
}
}
[Serializable]
public class P: CollectionBase,ISerializable,
IDeserializationCallback {
public P() {
List.Add(new PText("t1"));
List.Add(new PText("t2"));
}
private PText[] t = null;
public P(SerializationInfo info, StreamingContext context) {
// deserialize the array into the private array reference.
// once OnDeserialization() is called, we can walk through the
// array to rebuild the Llst
t = (PText[])info.GetValue("text", typeof(PText[]));
}
public void GetObjectData
(SerializationInfo info,StreamingContext context) {
PText[] t = new PText[List.Count];
List.CopyTo(t,0);
info.AddValue("text",t);
}
void IDeserializationCallback.OnDeserialization(Object sender) {
// all objects have been deserialized, now we can walk
// through the array, and add the itmes back ino the list
foreach (PText ptext in t) {
List.Add(ptext);
}
t = null; // clear the array reference so the array
// can be garbage collected
}
}
[Serializable]
public class PText : ISerializable {
string _t = "test1";
public PText() {
}
public PText(string str) {
_t = str;
}
public PText(SerializationInfo info, StreamingContext context) {
_t = (string)info.GetValue("text", typeof(string));
}
public void GetObjectData (SerializationInfo info,
StreamingContext context) {
info.AddValue("text",_t);
}
public string Text {
get {
return _t;
}
set {
_t = value;
}
}
}
class MyBinder : SerializationBinder {
public MyBinder(){;}
public override Type BindToType(string assemblyName,
string typeName) {
return System.Type.GetType(typeName);
}
}
}
//=========================================================