Click here to Skip to main content
15,846,091 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello all,

I'm having some sort of issue ( probably my understanding ) with serialization. I did some searching, and while there is a lot of discussion on this exception, none seemed to be of the nature I'm experiencing.

First, to get beyond the shortcomings of the ICloneable, I've instead created a static utility function as such:
public class Util
{
public static T DeepClone<T>( T objectToClone )
{
	using( MemoryStream stream = new MemoryStream() )
	{
		BinaryFormatter formatter = new BinaryFormatter();
		formatter.Serialize( stream, objectToClone );
		stream.Position = 0;
		return (T)formatter.Deserialize( stream );
	}
}
}

Pretty bread and butter stuff and it works as expected.

Where I'm having problems is when calling my DeepClone method from within a class I derived from TabPage ( we'll call it MyTabPage ). It's called from within a mouse button handler, and simplified it looks like this.
foreach( MyBaseObject member in selectedMembers )
{
    // Add a copy of the member to the super group's list.
    superGroup.AddMember( Util.DeepClone<MyBaseObject >( member ) );
}


... where selectedMembers is a field withing MyTabOject and is a List<> of MyBaseObject, and the MyBaseObject class is in fact decorated with the [Serializable] attribute.

The code compiles just fine, but when executed it throws an exception stating that MyTabPage is not marked as serializable. This confuses me. Why does the compiler care about MyTabPage ? Shouldn't it consider only the type being passed to my DeepClone() utility method?
Posted
Updated 2-Sep-10 16:02pm
v2
Comments
AspDotNetDev 2-Sep-10 18:16pm    
Are the items stored in the list of type MyBaseObject, or are they of a type derived from MyBaseObject? I suspect that could be your issue, but not sure enough to post it as an answer rather than just a comment.
RWey 2-Sep-10 21:15pm    
First, I fixed a typo in the call to DeepClone() ... sorry. I think, nevertheless, you get the gist.

And yes ... selectedMembers, while a list of MyBaseObject, does contain derivatives of MyBaseObject.

Again, tho, I'm puzzled as to why the run-time thinks the serialization has anything to do with the TabPage from which I'm calling the DeepClone() method. I would think that all it should care about is the type of class specified in the DeepClone( ... ) call. Even if the serialization is having problems when it encounters derived types of MyBaseObject, I would certainly think the thrown exception would state something a little more germain ... not complain that the TabPage making the call isn't marked as serializable.

One suspicion I had regarding the strange error was that selectedMembers was declared as a field within my TabPage derivative. To test this, I moved selectedMembers into the "superGroup" ( which is derived from MyBaseObject ), and basically moved the foreach iterator into the superGroup as well. Thus, all serializing was contained within a MyBaseObject derivative, with the only link to the TabPage being a simple method call to "Copy those items now". That threw the same exception ... again complaining about the TabPage not being marked serializable.

It makes no sense. Obviously I'm missing something.

BTW, I'm using VS2005.
Robert Zieroth 2-Sep-10 22:39pm    
What type of application is this in? a WinForms app?
What kind of objects are the derived classes of MyBaseObject? What I mean are they some sort of UI control for example a custom checkbox type of control?

OK, I just figured out my problem. First I'll say, it's nothing you guys missed ... rather, it was my lack of posting complete code as there was simply too much to keep it simple. Here's the problem in the constructor of a SuperGroup():

[Serializable]
public sealed class SuperGroupObject : GroupCadObject
{
    CadPage  cadPage;
    
    public SuperGroup( CadPage cadPage )
    {
        this.cadPage = cadPage;
    }
...


For reasons I won't go into detail about, it's necessary for the SuperGroup to be aware of its owning CadPage ... there's some information that must flow up hill to the owning page.

As you can see, therein lies the mysterious linkage to the CadPage. Even though I wasn't trying to directly serialize the SuperGroup ( rather, just members in its list of BaseCadObjects ), apparently the connection spills through because SuperGroup is ultimately derived from a BaseCadObject.

To fix the problem, it requires this:
[Serializable]
public sealed class SuperGroupObject : GroupCadObject
{
    [Nonserialize]
    CadPage  cadPage;

    public SuperGroup( CadPage cadPage )
    {
        this.cadPage = cadPage;
    }
...



I humbly eat my crow.

Thanks for you time and consideration.
 
Share this answer
 
v3
Comments
AspDotNetDev 2-Sep-10 23:42pm    
Reason for my vote of 5
Yay for apples on heads and sweat on brows!
Robert,
This is a WinForms app. Specifically, I'm writing a circuit board CAD application. If I ever finish it, great! If not, no loss as it's good C#/.NET exercise.

The BaseCadObject is not a control or derived from anything else. It's an abstract class that, of course, contains all the (abstract and/or virtual) properties and methods of items one might draw when creating schematics or PCBs. It is marked as [serializable] and so are all it's derivatives: Line, Pad, Label, Group, and SuperGroup. A group is different in that it includes a List<> of BaseCadObjects ... for simplifying the grouping of graphical objects. The SuperGroup becomes THE main group, or "file" which can be saved to disk by simply serializing it.

For the drawing surface, I include one empty TabControl filling the WinForm client area. Each file is then a "CadPage" derived from TabPage, where in the constructor I instantiate a PicturBox ( for rendering efficiency ) and attach the necessary paint and mouse handlers. Pretty simple stuff, if not tedious.

In the original problem/example, "selectedItems" is a field of CadPage and simply a list of BaseCadObjects that reference other objects in the SuperGroup (also a field of CadPage), and when you CTRL+drag the mouse when items are selected, one must copy all selected items ... hense the foreach iterator using the Util.DeepCopy() method to add them to the SuperGroup.

So, again, you can see that this copy mechanism should have nothing at all to do with serializing the CadPage ( derived from TabPage ). As shown, I'm directing the Util.DeepCopy() at BaseCadObjects, which ARE all marked as serializable. Nothing special about these objects. No delegate/events, no special interfaces, just simple objects containing a few properties and methods.

I just don't get it. This has to be some sort of run-time context issue, where serialization is aware of the thread/context from which it is called. If that's one of its operations constraints, it's about as useless as the IClonable interface I avoided. Very frustrating.

Thanks for any help. This novice appreciates it.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900