This is another funny problem related to serialization. Have you serialized a class and when deserialized again all the field values are set to default values? Well, check if this is your case:
If you have a class (Class1) that inherits from another one that is ISerializable (i.e. HashTable),
then you MUST write a constructor to handle SerializationInfo:
[Serializable]
class Class1: Hashtable
{
public Class1(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
public Class1()
{
}
protected int number;
private int othernumber;
public string text;
public int OtherNumber
{
get
{
return othernumber;
}
set
{
othernumber = value;
}
}
public int Number
{
get
{
return number;
}
set
{
number = value;
}
}
}
What’s the problem related to this?. Well, write a short win application with a button to test:
private void button1_Click(object sender, EventArgs e)
{
Class1 obj = new Class1();
obj.Number = 99;
obj.OtherNumber = 100;
obj.text = "hello";
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
byte[] serializedObject;
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
//formatter.FilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.
formatter.Serialize(memoryStream, obj);
serializedObject = memoryStream.GetBuffer();
System.IO.MemoryStream memoryStream2 = new System.IO.MemoryStream(serializedObject);
Class1 obj2 = (Class1)formatter.Deserialize(memoryStream2);
}
And now, check the obj2: None of the values where properly retrieved! Why?
Well, as the Class1 class inherits from hashtable and hastable implements ISerializable, you need to write the special constructor above, but once you write the constructor, you are telling .net that you will be in charge of saving the data you really want to save… If you save no information for your fields, no data is saved when serialized, so no data is retrieved when deserialized.
The quick (and dirty ;) ) way to solve this: Use reflection to automatically traverse the properties and save them instead of write code to save them one by one:
[Serializable]
class Class1: Hashtable
{
public Class1(SerializationInfo info, StreamingContext context)
: base(info, context)
{
FieldInfo[] fields = this.GetFields(this);
foreach (FieldInfo fieldInfo in fields)
{
Object obj = info.GetValue(fieldInfo.Name,fieldInfo.FieldType);
fieldInfo.SetValue(this,obj);
}
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
FieldInfo[] fields = this.GetFields(this);
foreach (FieldInfo fieldInfo in fields)
{
info.AddValue(fieldInfo.Name,fieldInfo.GetValue(this));
}
base.GetObjectData(info, context);
}
public Class1()
{
}
protected int number;
private int othernumber;
public string text;
public int OtherNumber
{
get
{
return othernumber;
}
set
{
othernumber = value;
}
}
public int Number
{
get
{
return number;
}
set
{
number = value;
}
}
private FieldInfo[] GetFields(object obj)
{
FieldInfo[] fields =
obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
return fields;
}
}
Note that I’ve include the BindingFlags I’ve added to obtain the fields. This can be modified if other kind of filters are needed.