GetValue and ISerialization, object not constructed??

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I've got this strange problem in a class that uses ISerializable to serialize a NameValueCollection
During deserialization, in the object constructor, after using GetValue to get the NameValueCollection from SerializationInfo, the NameValueCollection is not usable. It throws a NullReferenceException from pretty much any property/method. It is usable after the object is deserialized, but not in the constructor. I've narrowed down the code to a small sample. Can an object not be used during the deserialization constructor? I haven't found any docs that say this shouldn't be allowed

Code sample
================Snip==============

using System
using System.Collections.Specialized
using System.IO
using System.Runtime.Serialization
using System.Runtime.Serialization.Formatters.Binary
using System.Runtime.Serialization.Formatters.Soap

namespace SerializationTes

[Serializable
public class SerializeMe : ISerializabl


private NameValueCollection values

public SerializeMe()
values = new NameValueCollection()
values.Add("string1", "hi")
values.Add("string2", "there")


protected SerializeMe(SerializationInfo info, StreamingContext context)
values = (NameValueCollection) info.GetValue("values", typeof(NameValueCollection))
PrintMe(); // <-- why can this not access values??
// throws null reference exception inside values.get_Count(


static void Main(string[] args


// create one, print i
SerializeMe serializeme = new SerializeMe()

serializeme.PrintMe()

// serialize it to fil
FileStream file = new FileStream("c:\\test.txt", FileMode.Create)
SoapFormatter formatter = new SoapFormatter()

formatter.Serialize(file, serializeme)
file.Close()
serializeme = null

// read it back and try to prin
file = new FileStream("c:\\test.txt", FileMode.Open)
try
serializeme = (SerializeMe) formatter.Deserialize(file)
serializeme.PrintMe(); // <-- this works, what is different here than print in constructor
} catch(Exception e)
Console.WriteLine("Failed: " + e)

file.Close()


public void PrintMe()
Console.WriteLine("Items: " + values.Count)
foreach(string sKey in values.Keys)
Console.WriteLine("Key: " + sKey + ": " + values[sKey])



public void GetObjectData(SerializationInfo info, StreamingContext context)
info.AddValue("values", values)
 
Hey

Your call to PrintMe in the constructor for SerializeMe does not work because your object is created inside out so the NameValueCollection has not yet been fully constructed when you call PrintMe

I have tried to find a solution for this. I tried letting SerializeMe implement IDeserializationCallback and the call PrintMe in the implementation of OnDeserialization. This does not seem to work. However, NameValueCollection also implements IDeserializationCallback so I tried creating a new class inheriting NameValueCollection and then overriding NameValueCollection.OnDeserialization. This ALMOST works since I am able to get the correct item count and I am also able to extract the keys. However, for some strange reason, if I try to extract the values of the NameValueCollection, I get an exception

Instead of inheriting from NameValueCollection I then tried inheriting from Hashtable. In the override of OnDeserialization I can now extract and print the values of the hashtable. So Hashtable and NameValueCollection do not behave the same way

Here is my code

[Serializable
public class NameValueCollectionEx : System.Collections.Hashtabl

public NameValueCollectionEx(
: base(



protected NameValueCollectionEx(SerializationInfo info, StreamingContext context)
: base(info, context



public override void OnDeserialization(object sender

base.OnDeserialization (sender)

Console.WriteLine("Items: " + this.Count)
foreach (string key in this.Keys)

Console.WriteLine("Key: " + key + "->" + this[key].ToString())




[Serializable
public class SerializeMe : ISerializable, IDeserializationCallbac

private NameValueCollectionEx values

public SerializeMe()

values = new NameValueCollectionEx()
values.Add("string1", "hi")
values.Add("string2", "there")


protected SerializeMe(SerializationInfo info, StreamingContext context)

values = (NameValueCollectionEx) info.GetValue("values", typeof(NameValueCollectionEx))


// The rest of your code goes here..


Regards, Jakob
 
After playing around awhile I finally found a little blurb about IDeserializationCallback and that "accessing member values is bad." during deserialization. Then I discovered that IDeserializationCallback doesn't guarantee any call order, so it's quite useless and had the exact same problem. Seems that serialization can't work in a general way once objects start implementing ISerializable

I've resorted to never storing objects in the SerializationInfo. It sure is alot more code to reimplement serialization on every object that is already serializable :
 
Back
Top