Serializing reference-type members of derived dataset

  • Thread starter Thread starter Mark Rendle
  • Start date Start date
M

Mark Rendle

If I derive a [Serializable] class from DataSet and add a value-type member
to it, then that member is serialized (using SoapFormatter) without a
problem. However, if I add a reference-type member it does not get
serialized, even though the class for the member has the Serializable
attribute. Is there any way I can get the reference-type members to be
serialized?

Cheers,
Mark
 
Sahil Malik said:
I think I can answer this .. to save me some time investigating this ..
what reference type exactly did you use?

Can you paste the inherited class from dataset code that doesn't work?

Here:

[Serializable]
public class XDataSet : DataSet
{
private string str;
private ArrayList list;

public XDataSet() : base()
{
DataTable dt = new DataTable("X");
this.Tables.Add(dt);

dt.Columns.Add("X1", typeof(int));
dt.Columns.Add("X2", typeof(string));
}

protected XDataSet(SerializationInfo si, StreamingContext sc) : base(si,
sc) {}

public string Str
{
get { return str; }
set { str = value; }
}

public ArrayList List
{
get { return list; }
}
}

I've also tried it with a Serializable class of my own which didn't work
either.

Thanks,
Mark
 
The problem is the ISerializable protected constructor you have. Remove
that.

Here is some code that worked.

#region Using directives
using System;
using System.Collections;
using System.Text;

using System.Data ;
using System.Data.SqlClient;
using System.Runtime.Serialization.Formatters.Soap ;
using System.IO ;
#endregion

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SoapFormatter sf = new SoapFormatter();
FileStream fs = new FileStream("c:\\1.xml", FileMode.Create);
XDataSet ds = new XDataSet() ;
sf.Serialize(fs, ds);
fs.Close();
}
}

[Serializable]
public class XDataSet : DataSet
{
private ArrayList list;

public XDataSet()
{
DataTable dt = new DataTable("X");
this.Tables.Add(dt);

dt.Columns.Add("X1", typeof(int));
dt.Columns.Add("X2", typeof(string));

list = new ArrayList();
}

public ArrayList List
{
get { return list; }
}
}
}

The above is .NET framework 2.0, but I'd be hardpressed to imagine if it
didn't work in 1.1.

- Sahil Malik
http://codebetter.com/blogs/sahil.malik/



Mark Rendle said:
Sahil Malik said:
I think I can answer this .. to save me some time investigating this ..
what reference type exactly did you use?

Can you paste the inherited class from dataset code that doesn't work?

Here:

[Serializable]
public class XDataSet : DataSet
{
private string str;
private ArrayList list;

public XDataSet() : base()
{
DataTable dt = new DataTable("X");
this.Tables.Add(dt);

dt.Columns.Add("X1", typeof(int));
dt.Columns.Add("X2", typeof(string));
}

protected XDataSet(SerializationInfo si, StreamingContext sc) : base(si,
sc) {}

public string Str
{
get { return str; }
set { str = value; }
}

public ArrayList List
{
get { return list; }
}
}

I've also tried it with a Serializable class of my own which didn't work
either.

Thanks,
Mark
 
It won't deserialize without the constructor though.

Added this code:

ds = null;

//Opens file "data.xml" and deserializes the object from it.
fs = File.Open("C:\\1.xml", FileMode.Open);
sf = new SoapFormatter();

ds = (XDataSet)sf.Deserialize(fs);
fs.Close();

and got this Exception:

An unhandled exception of type
'System.Runtime.Serialization.SerializationException' occurred in
mscorlib.dll

Additional information: The constructor to deserialize an object of type
ConsoleApplication1.XDataSet was not found.

:(

Mark
 
It actually will deserialize without that constructor. That constructor is
required only when you implement ISerializable. Try implementing
ISerializable, and add GetObjectData .. then you'll get no problem 2 way
serialization. You can't do a midway approach, unfortunately interfaces have
no way of enforcing protected constructors.
 
It's easy, implement ISerializable. it'll add the GetObjectData. Then just
do info.AddValue("..","..") .. nothing special just because it's a dataset.

But coming back to my main point, simply putting the attribute
[Serializable] should work as long as you don't use non-serializable member
variables, and even if you do, you can get around that using the
[NonSerialized] attribute.

- Sahil Malik
http://codebetter.com/blogs/sahil.malik/
 
Sahil Malik said:
It's easy, implement ISerializable. it'll add the GetObjectData. Then just
do info.AddValue("..","..") .. nothing special just because it's a
dataset.

Thanks, I'll give it a try.
But coming back to my main point, simply putting the attribute
[Serializable] should work as long as you don't use non-serializable
member
variables

It really doesn't, though. Honestly. The following code (at least in
Framework 1.1) will throw a SerializationException: "The constructor to
deserialize an object of type ConsoleApplication1.XDataSet was not found."

#region Using directives
using System;
using System.Collections;
using System.Data;
using System.Runtime.Serialization.Formatters.Soap ;
using System.IO ;
#endregion

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SoapFormatter sf = new SoapFormatter();
FileStream fs = new FileStream("data.xml", FileMode.Create);
XDataSet ds = new XDataSet() ;
sf.Serialize(fs, ds);
fs.Close();

//Empties obj.
ds = null;

//Opens file "data.xml" and deserializes the object from it.
fs = File.Open("data.xml", FileMode.Open);
sf = new SoapFormatter();

ds = (XDataSet)sf.Deserialize(fs);
fs.Close();
}
}

[Serializable]
public class XDataSet : DataSet
{
private ArrayList list;

public XDataSet()
{
DataTable dt = new DataTable("X");
this.Tables.Add(dt);

dt.Columns.Add("X1", typeof(int));
dt.Columns.Add("X2", typeof(string));

list = new ArrayList();
}

public ArrayList List
{
get { return list; }
}
}
}
 
Okay I believe ya. I just don't have a machine to test this on. I will be at
a client who is on .NET 1.1 in March. Can u send me a message thru my blog
and I'll remember to email u when I have a .NET 1.1 answer.

- Sahil Malik
http://codebetter.com/blogs/sahil.malik/


Mark Rendle said:
Sahil Malik said:
It's easy, implement ISerializable. it'll add the GetObjectData. Then
just
do info.AddValue("..","..") .. nothing special just because it's a
dataset.

Thanks, I'll give it a try.
But coming back to my main point, simply putting the attribute
[Serializable] should work as long as you don't use non-serializable
member
variables

It really doesn't, though. Honestly. The following code (at least in
Framework 1.1) will throw a SerializationException: "The constructor to
deserialize an object of type ConsoleApplication1.XDataSet was not found."

#region Using directives
using System;
using System.Collections;
using System.Data;
using System.Runtime.Serialization.Formatters.Soap ;
using System.IO ;
#endregion

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SoapFormatter sf = new SoapFormatter();
FileStream fs = new FileStream("data.xml", FileMode.Create);
XDataSet ds = new XDataSet() ;
sf.Serialize(fs, ds);
fs.Close();

//Empties obj.
ds = null;

//Opens file "data.xml" and deserializes the object from it.
fs = File.Open("data.xml", FileMode.Open);
sf = new SoapFormatter();

ds = (XDataSet)sf.Deserialize(fs);
fs.Close();
}
}

[Serializable]
public class XDataSet : DataSet
{
private ArrayList list;

public XDataSet()
{
DataTable dt = new DataTable("X");
this.Tables.Add(dt);

dt.Columns.Add("X1", typeof(int));
dt.Columns.Add("X2", typeof(string));

list = new ArrayList();
}

public ArrayList List
{
get { return list; }
}
}
}
 
Back
Top