K
ktrvnbq02
Hi,
I have a serializable class that has a NameValueCollection as a member
object. As part of the deserialization process, via a callback during
deserialization, the class needs to call various methods on the
NameValueCollection. This is currently failing due to the internal
state of NameValueCollection not being available, despite having a
reference to the object.
I have tried default serialization and implementing custom
serialization via ISerializable. I have also tried implementing the
callback using IDeserializationCallback and via the OnDeserialized
attribute in .NET 2.0.
I have simplified the test case down to the following, and I'd be
grateful for any comments as to why it does not work. Note that if I
comment out PrintCount() in the OnDeserialization method, the call in
Main() does succeed.
---------------------8<---------------------
using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Testcase
{
class Program
{
static void Main(string[] args)
{
try
{
NVCWrapper nvcWrapper = new NVCWrapper();
// Serialize
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, nvcWrapper);
// Deserialize
memoryStream.Seek(0, SeekOrigin.Begin);
NVCWrapper dsNvcWrapper = (NVCWrapper)
formatter.Deserialize(memoryStream);
// Print count
dsNvcWrapper.PrintCount();
}
catch (Exception ex)
{
Console.Write("Exception:");
while (ex != null)
{
Console.WriteLine(Environment.NewLine);
Console.WriteLine(ex.GetType().ToString());
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
ex = ex.InnerException;
}
}
finally
{
Console.WriteLine("Press a key to exit...");
Console.Read();
}
}
}
[Serializable]
public sealed class NVCWrapper : IDeserializationCallback
{
private NameValueCollection mNVC = new NameValueCollection();
public NVCWrapper()
{
mNVC.Add("TestName", "TestValue");
}
public void PrintCount()
{
Console.WriteLine("Count = " + mNVC.Count.ToString());
}
#region IDeserializationCallback Members
public void OnDeserialization(object sender)
{
PrintCount(); // NullReferenceException thrown from
NameValueCollection's Count property.
}
#endregion
}
}
---------------------8<---------------------
Now, if I swap the implementation of NameValueCollection for the
following stub class (updating the inline instantiation of
NameValueCollection to MyNameValueCollection in NVCWrapper to point to
the new class), the deserialization of NVCWrapper succeeds and no
exception is thrown in OnDeserialization:
---------------------8<---------------------
[Serializable]
public sealed class MyNameValueCollection
{
ArrayList mNames = new ArrayList();
ArrayList mValues = new ArrayList();
public MyNameValueCollection()
{
}
public void Add(string name, string val)
{
mNames.Add(name);
mValues.Add(val);
}
public int Count
{
get { return mNames.Count; }
}
}
---------------------8<---------------------
I'm just trying to understand what is wrong with the original test
case, and under what circumstances (if any) you can rely on member
objects being fully instantiated themselves when in a deserialization
callback.
Regards,
Matt
I have a serializable class that has a NameValueCollection as a member
object. As part of the deserialization process, via a callback during
deserialization, the class needs to call various methods on the
NameValueCollection. This is currently failing due to the internal
state of NameValueCollection not being available, despite having a
reference to the object.
I have tried default serialization and implementing custom
serialization via ISerializable. I have also tried implementing the
callback using IDeserializationCallback and via the OnDeserialized
attribute in .NET 2.0.
I have simplified the test case down to the following, and I'd be
grateful for any comments as to why it does not work. Note that if I
comment out PrintCount() in the OnDeserialization method, the call in
Main() does succeed.
---------------------8<---------------------
using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Testcase
{
class Program
{
static void Main(string[] args)
{
try
{
NVCWrapper nvcWrapper = new NVCWrapper();
// Serialize
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, nvcWrapper);
// Deserialize
memoryStream.Seek(0, SeekOrigin.Begin);
NVCWrapper dsNvcWrapper = (NVCWrapper)
formatter.Deserialize(memoryStream);
// Print count
dsNvcWrapper.PrintCount();
}
catch (Exception ex)
{
Console.Write("Exception:");
while (ex != null)
{
Console.WriteLine(Environment.NewLine);
Console.WriteLine(ex.GetType().ToString());
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
ex = ex.InnerException;
}
}
finally
{
Console.WriteLine("Press a key to exit...");
Console.Read();
}
}
}
[Serializable]
public sealed class NVCWrapper : IDeserializationCallback
{
private NameValueCollection mNVC = new NameValueCollection();
public NVCWrapper()
{
mNVC.Add("TestName", "TestValue");
}
public void PrintCount()
{
Console.WriteLine("Count = " + mNVC.Count.ToString());
}
#region IDeserializationCallback Members
public void OnDeserialization(object sender)
{
PrintCount(); // NullReferenceException thrown from
NameValueCollection's Count property.
}
#endregion
}
}
---------------------8<---------------------
Now, if I swap the implementation of NameValueCollection for the
following stub class (updating the inline instantiation of
NameValueCollection to MyNameValueCollection in NVCWrapper to point to
the new class), the deserialization of NVCWrapper succeeds and no
exception is thrown in OnDeserialization:
---------------------8<---------------------
[Serializable]
public sealed class MyNameValueCollection
{
ArrayList mNames = new ArrayList();
ArrayList mValues = new ArrayList();
public MyNameValueCollection()
{
}
public void Add(string name, string val)
{
mNames.Add(name);
mValues.Add(val);
}
public int Count
{
get { return mNames.Count; }
}
}
---------------------8<---------------------
I'm just trying to understand what is wrong with the original test
case, and under what circumstances (if any) you can rely on member
objects being fully instantiated themselves when in a deserialization
callback.
Regards,
Matt