serialization bug

A

Aaron Clamage

Hi,

Could someone please confirm the following?

I think I have found a subtle .NET serialization bug. It occurs when object
has a list of items containing another object of the same type and both
objects have a non-static member reference to some other static object. In
this case, I get an InvalidArgument exception when I try to access the
non-static member of the child class. I've included a code sample to
clarify. This "bug" is causing a major problem for me. So, if anyone could
confirm it or let me know if I'm doing something wrong, I would be very
appreciative.

Thanks,
Aaron

Here is the sample

[Serializable]
public class A {
private ArrayList children;
private static Pen DPEN = Pens.Black;
private Pen pen = DPEN;

public A() {
children = new ArrayList();
children.Add(new D());
}

public void AddChild(A a) {
children.Add(a);
}

public A Child {
get { return (A)children[0]; }
}

public Pen Pen {
get { return pen; }
}
}

public class PenSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info,
StreamingContext context) {
Pen pen = (Pen)obj;

info.AddValue("pencolor", pen.PenType == PenType.SolidColor ? pen.Color :
Color.Empty);
}

public Object SetObjectData(Object obj, SerializationInfo info,
StreamingContext context, ISurrogateSelector selector) {
return (Pen)info.GetValue("pencolor", typeof(Pen));
}
}

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

A a = new A();
A an = new A();
a.AddChild(an);

BinaryFormatter bFormatter = new BinaryFormatter();
SurrogateSelector s = new SurrogateSelector();
s.AddSurrogate(typeof(Pen), new
StreamingContext(StreamingContextStates.All), new PenSurrogate());
bFormatter.SurrogateSelector = s;
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, a);
stream.Seek(0, SeekOrigin.Begin);
A copy = (A)bFormatter.Deserialize(stream);

System.Console.WriteLine(copy.Pen.Color.ToString());
System.Console.WriteLine(copy.Child.Pen.Color.ToString()); //Causes an
InvalidArgument Exception
}
 
N

Nicholas Paldino [.NET/C# MVP]

Aaron,

The problem is with your Serialization surrogate. When you assign the
data, you are storing an instance of the color of the Pen. When returning,
you are taking that instance (a Color structure) and trying to cast it to a
pen. What you should do is create a new Pen and set the color, then return
that.

Hope this helps.
 
A

Aaron Clamage

Sorry, that was a typo. But, it is not the problem. Even if the following
line is in the SetObjectData method the problem still occurs. In fact, it
occurs for any non-static reference to a static member.

return new Pen(Color.Black);


Nicholas Paldino said:
Aaron,

The problem is with your Serialization surrogate. When you assign the
data, you are storing an instance of the color of the Pen. When returning,
you are taking that instance (a Color structure) and trying to cast it to a
pen. What you should do is create a new Pen and set the color, then return
that.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Aaron Clamage said:
Hi,

Could someone please confirm the following?

I think I have found a subtle .NET serialization bug. It occurs when object
has a list of items containing another object of the same type and both
objects have a non-static member reference to some other static object. In
this case, I get an InvalidArgument exception when I try to access the
non-static member of the child class. I've included a code sample to
clarify. This "bug" is causing a major problem for me. So, if anyone could
confirm it or let me know if I'm doing something wrong, I would be very
appreciative.

Thanks,
Aaron

Here is the sample

[Serializable]
public class A {
private ArrayList children;
private static Pen DPEN = Pens.Black;
private Pen pen = DPEN;

public A() {
children = new ArrayList();
children.Add(new D());
}

public void AddChild(A a) {
children.Add(a);
}

public A Child {
get { return (A)children[0]; }
}

public Pen Pen {
get { return pen; }
}
}

public class PenSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info,
StreamingContext context) {
Pen pen = (Pen)obj;

info.AddValue("pencolor", pen.PenType == PenType.SolidColor ?
pen.Color
:
Color.Empty);
}

public Object SetObjectData(Object obj, SerializationInfo info,
StreamingContext context, ISurrogateSelector selector) {
return (Pen)info.GetValue("pencolor", typeof(Pen));
}
}

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

A a = new A();
A an = new A();
a.AddChild(an);

BinaryFormatter bFormatter = new BinaryFormatter();
SurrogateSelector s = new SurrogateSelector();
s.AddSurrogate(typeof(Pen), new
StreamingContext(StreamingContextStates.All), new PenSurrogate());
bFormatter.SurrogateSelector = s;
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, a);
stream.Seek(0, SeekOrigin.Begin);
A copy = (A)bFormatter.Deserialize(stream);

System.Console.WriteLine(copy.Pen.Color.ToString());
System.Console.WriteLine(copy.Child.Pen.Color.ToString()); //Causes an
InvalidArgument Exception
}
 
N

Nicholas Paldino [.NET/C# MVP]

Aaron,

Can you post the definition of D? I would ignore it, but your Child
property returns the first child which is set in the constructor.

Also, if D derives from A, then I can't see how this doesn't result in
an infinite loop (A creates an instance of D, which int turn, creates an
instance of A, etc, etc).

If D doesn't derive from A, then this is an error, because getting the
property A will result in an invalid cast exception.

Could you please post the complete source which compiles?

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Aaron Clamage said:
Sorry, that was a typo. But, it is not the problem. Even if the following
line is in the SetObjectData method the problem still occurs. In fact, it
occurs for any non-static reference to a static member.

return new Pen(Color.Black);


message news:#[email protected]...
Aaron,

The problem is with your Serialization surrogate. When you assign the
data, you are storing an instance of the color of the Pen. When returning,
you are taking that instance (a Color structure) and trying to cast it
to
a
pen. What you should do is create a new Pen and set the color, then return
that.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Aaron Clamage said:
Hi,

Could someone please confirm the following?

I think I have found a subtle .NET serialization bug. It occurs when object
has a list of items containing another object of the same type and both
objects have a non-static member reference to some other static
object.
In
this case, I get an InvalidArgument exception when I try to access the
non-static member of the child class. I've included a code sample to
clarify. This "bug" is causing a major problem for me. So, if anyone could
confirm it or let me know if I'm doing something wrong, I would be very
appreciative.

Thanks,
Aaron

Here is the sample

[Serializable]
public class A {
private ArrayList children;
private static Pen DPEN = Pens.Black;
private Pen pen = DPEN;

public A() {
children = new ArrayList();
children.Add(new D());
}

public void AddChild(A a) {
children.Add(a);
}

public A Child {
get { return (A)children[0]; }
}

public Pen Pen {
get { return pen; }
}
}

public class PenSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info,
StreamingContext context) {
Pen pen = (Pen)obj;

info.AddValue("pencolor", pen.PenType == PenType.SolidColor ?
pen.Color
:
Color.Empty);
}

public Object SetObjectData(Object obj, SerializationInfo info,
StreamingContext context, ISurrogateSelector selector) {
return (Pen)info.GetValue("pencolor", typeof(Pen));
}
}

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

A a = new A();
A an = new A();
a.AddChild(an);

BinaryFormatter bFormatter = new BinaryFormatter();
SurrogateSelector s = new SurrogateSelector();
s.AddSurrogate(typeof(Pen), new
StreamingContext(StreamingContextStates.All), new PenSurrogate());
bFormatter.SurrogateSelector = s;
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, a);
stream.Seek(0, SeekOrigin.Begin);
A copy = (A)bFormatter.Deserialize(stream);

System.Console.WriteLine(copy.Pen.Color.ToString());
System.Console.WriteLine(copy.Child.Pen.Color.ToString()); //Causes an
InvalidArgument Exception
}
 
A

Aaron Clamage

I apologize. I had been trying different things. But, you can ignore the
line referencing D. Here is the correct code sample illustrating the bug
(cut directly from the compiling project).

[Serializable]
public class A {
private ArrayList children;
private static Pen DPEN = Pens.Black;
private Pen pen = DPEN;

public A() {
children = new ArrayList();
}

public void AddChild(A a) {
children.Add(a);
}

public A Child {
get { return (A)children[0]; }
}

public Pen Pen {
get { return pen; }
}
}

public class PenSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info,
StreamingContext context) {
Pen pen = (Pen)obj;
info.AddValue("pencolor", pen.PenType == PenType.SolidColor ? pen.Color :
Color.Empty);
}

public Object SetObjectData(Object obj, SerializationInfo info,
StreamingContext context, ISurrogateSelector selector) {
return new Pen((Color)info.GetValue("pencolor", typeof(Color)));
}
}

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

A a = new A();
A an = new A();
a.AddChild(an);

BinaryFormatter bFormatter = new BinaryFormatter();
SurrogateSelector s = new SurrogateSelector();
s.AddSurrogate(typeof(Pen), new
StreamingContext(StreamingContextStates.All), new PenSurrogate());
bFormatter.SurrogateSelector = s;
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, a);
stream.Seek(0, SeekOrigin.Begin);
A copy = (A)bFormatter.Deserialize(stream);

System.Console.WriteLine(copy.Pen.Color.ToString());
System.Console.WriteLine(copy.Child.Pen.Color.ToString()); // Causes an
InvalidArgument exception
}

Nicholas Paldino said:
Aaron,

Can you post the definition of D? I would ignore it, but your Child
property returns the first child which is set in the constructor.

Also, if D derives from A, then I can't see how this doesn't result in
an infinite loop (A creates an instance of D, which int turn, creates an
instance of A, etc, etc).

If D doesn't derive from A, then this is an error, because getting the
property A will result in an invalid cast exception.

Could you please post the complete source which compiles?

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Aaron Clamage said:
Sorry, that was a typo. But, it is not the problem. Even if the following
line is in the SetObjectData method the problem still occurs. In fact, it
occurs for any non-static reference to a static member.

return new Pen(Color.Black);


message news:#[email protected]...
Aaron,

The problem is with your Serialization surrogate. When you assign the
data, you are storing an instance of the color of the Pen. When returning,
you are taking that instance (a Color structure) and trying to cast it
to
a
pen. What you should do is create a new Pen and set the color, then return
that.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Hi,

Could someone please confirm the following?

I think I have found a subtle .NET serialization bug. It occurs when
object
has a list of items containing another object of the same type and both
objects have a non-static member reference to some other static object.
In
this case, I get an InvalidArgument exception when I try to access the
non-static member of the child class. I've included a code sample to
clarify. This "bug" is causing a major problem for me. So, if anyone
could
confirm it or let me know if I'm doing something wrong, I would be very
appreciative.

Thanks,
Aaron

Here is the sample

[Serializable]
public class A {
private ArrayList children;
private static Pen DPEN = Pens.Black;
private Pen pen = DPEN;

public A() {
children = new ArrayList();
children.Add(new D());
}

public void AddChild(A a) {
children.Add(a);
}

public A Child {
get { return (A)children[0]; }
}

public Pen Pen {
get { return pen; }
}
}

public class PenSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info,
StreamingContext context) {
Pen pen = (Pen)obj;

info.AddValue("pencolor", pen.PenType == PenType.SolidColor ? pen.Color
:
Color.Empty);
}

public Object SetObjectData(Object obj, SerializationInfo info,
StreamingContext context, ISurrogateSelector selector) {
return (Pen)info.GetValue("pencolor", typeof(Pen));
}
}

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

A a = new A();
A an = new A();
a.AddChild(an);

BinaryFormatter bFormatter = new BinaryFormatter();
SurrogateSelector s = new SurrogateSelector();
s.AddSurrogate(typeof(Pen), new
StreamingContext(StreamingContextStates.All), new PenSurrogate());
bFormatter.SurrogateSelector = s;
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, a);
stream.Seek(0, SeekOrigin.Begin);
A copy = (A)bFormatter.Deserialize(stream);

System.Console.WriteLine(copy.Pen.Color.ToString());
System.Console.WriteLine(copy.Child.Pen.Color.ToString());
//Causes
an
InvalidArgument Exception
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top