By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,771 Members | 1,685 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,771 IT Pros & Developers. It's quick & easy.

Serializing instances of derived classes

P: n/a

Imagine one writing a class library CL1 for data storage.
He defines classes ‘DataItem’ and ‘DataRecord’ so that the latter contains
a collection of the former.
And he derives class ‘IntItem’ from ‘DataItem’

[XmlRoot ("DataItem")]
[XmlInclude (typeof (IntItem))]
public class DataItem
{
public DataItem() {}
public DataItem (string name)
{
_name = name;
}

private string _name;

[XmlAttribute]
public string Name
{
get { return _name; }
set { _name = value; }
}
}

[XmlRoot ("IntItem")]
public class IntItem : SerializeDerivedClass.DataItem
{
public IntItem(){}
public IntItem (string name, int intValue) : base (name)
{
_intValue = intValue;
}

private int _intValue;

[XmlAttribute ("IntValue")]
public int IntValue
{
get { return _intValue; }
set { _intValue = value; }
}
}

[XmlRoot ("DataRecord")]
public class DataRecord
{
public DataRecord() {}

private DataItem [] _data;

[XmlElement ("DataItem", typeof (DataItem))]
[XmlElement ("IntItem", typeof (IntItem))]
public DataItem [] Data
{
get { return _data; }
set { _data = value; }
}
}

Now the following code works fine.

DataRecord rec = new DataRecord ();
rec.Data = new DataItem [3];
rec.Data [0] = new DataItem ("DI-1");
rec.Data [1] = new IntItem ("II-1", 3);

XmlSerializer xser = new XmlSerializer (typeof (DataRecord));

xser.Serialize (Console.Out, rec);

Its output is

<DataRecord>
<DataItem Name="DI-1" />
<IntItem Name="II-1" IntValue="3" />
</DataRecord>

Now another developer creates another class library CL2 containing class
‘DoubleItem’
derived from ‘DataItem’. Of course, the second developer wishes the code
above
including the following line to work too

Rec.Data [2] = new DoubleItem (“DblI-1”, Math.PI);

[XmlRoot ("DoubleItem")]
public class DoubleItem : SerializeDerivedClass.DataItem
{
public DoubleItem(){}
public DoubleItem (string name, double doubleValue) : base (name)
{
_doubleValue = doubleValue;
}

private double _doubleValue;

[XmlAttribute ("DoubleValue")]
public double DoubleValue
{
get { return _doubleValue; }
set { _doubleValue = value; }
}
}

This should produce

<DataRecord>
<DataItem Name="DI-1" />
<IntItem Name="II-1" IntValue="3" />
<DoubleItem Name=”DblI-1” DoubleValue=”3.1415..”/>
</DataRecord>

Can this behavior be achieved without rebuilding the first class library
CL1?
Why 'DoubleItem' is "not expected" while every instance
of 'DoubleItem' is 'DataItem'?

Aleksei Guzev
Nov 12 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a
Aleksei,

Are you instantiating the XmlSerializer in CL1 or CL2?

If you are instantiating in CL1, then there is indeed no way to make
this work without rebuilding. Otherwise you could pass the Type
DoubleItem to the constructor of the XmlSerializer:

XmlSerializer xser = new XmlSerializer (typeof (DataRecord), new Type[]
{typeof(DoubleItem)});

However, this will probably not produce the XML format you're looking
for:

<?xml version="1.0" encoding="IBM437"?>
<DataRecord xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w
3.org/2001/XMLSchema-instance">
<DataItem Name="DI-1" />
<IntItem Name="II-1" IntValue="3" />
<DataItem xsi:type="DoubleItem" Name="DblI-1"
DoubleValue="3.1415926535897931"
/>
</DataRecord>

The DoubleItem is serialized as a <DataItem> element.

If you need to customize the format, then you can override the
serialization attributes on the Data property in the DataRecord class.
The code goes like this:

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes dataAttributes = new XmlAttributes();
dataAttributes.XmlElements.Add( new XmlElementAttribute( "DoubleItem",
typeof(DoubleItem) ) );
dataAttributes.XmlElements.Add( new XmlElementAttribute( "DataItem",
typeof(DataItem) ) );
dataAttributes.XmlElements.Add( new XmlElementAttribute( "IntItem",
typeof(IntItem) ) );
overrides.Add( typeof( DataRecord ), "Data", dataAttributes );

XmlSerializer xser = new XmlSerializer (typeof (DataRecord), overrides,
new Type[0], null, "" );

xser.Serialize (Console.Out, rec);

and you get the format you were looking for:

<?xml version="1.0" encoding="IBM437"?>
<DataRecord xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w
3.org/2001/XMLSchema-instance">
<DataItem Name="DI-1" />
<IntItem Name="II-1" IntValue="3" />
<DoubleItem Name="DblI-1" DoubleValue="3.1415926535897931" />
</DataRecord>

Notice here the attributes in the XmlAttributeOverrides collection
override all attributes in the original class. They are not added, to
the existing ones. You have to add the attributes for the DataItem and
IntItem types again, too.

HTH,
Christoph Schittko
MS MVP XML
http://weblogs.asp.net/cschittko
-----Original Message-----
From: Aleksei Guzev [mailto:al***********@bigfoot.com]
Posted At: Thursday, November 25, 2004 4:13 AM
Posted To: microsoft.public.dotnet.xml
Conversation: Serializing instances of derived classes
Subject: Serializing instances of derived classes
Imagine one writing a class library CL1 for data storage.
He defines classes 'DataItem' and 'DataRecord' so that the latter contains a collection of the former.
And he derives class 'IntItem' from 'DataItem'

[XmlRoot ("DataItem")]
[XmlInclude (typeof (IntItem))]
public class DataItem
{
public DataItem() {}
public DataItem (string name)
{
_name = name;
}

private string _name;

[XmlAttribute]
public string Name
{
get { return _name; }
set { _name = value; }
}
}

[XmlRoot ("IntItem")]
public class IntItem : SerializeDerivedClass.DataItem
{
public IntItem(){}
public IntItem (string name, int intValue) : base (name)
{
_intValue = intValue;
}

private int _intValue;

[XmlAttribute ("IntValue")]
public int IntValue
{
get { return _intValue; }
set { _intValue = value; }
}
}

[XmlRoot ("DataRecord")]
public class DataRecord
{
public DataRecord() {}

private DataItem [] _data;

[XmlElement ("DataItem", typeof (DataItem))]
[XmlElement ("IntItem", typeof (IntItem))]
public DataItem [] Data
{
get { return _data; }
set { _data = value; }
}
}

Now the following code works fine.

DataRecord rec = new DataRecord ();
rec.Data = new DataItem [3];
rec.Data [0] = new DataItem ("DI-1");
rec.Data [1] = new IntItem ("II-1", 3);

XmlSerializer xser = new XmlSerializer (typeof (DataRecord));

xser.Serialize (Console.Out, rec);

Its output is

<DataRecord>
<DataItem Name="DI-1" />
<IntItem Name="II-1" IntValue="3" />
</DataRecord>

Now another developer creates another class library CL2 containing class 'DoubleItem'
derived from 'DataItem'. Of course, the second developer wishes the code above
including the following line to work too

Rec.Data [2] = new DoubleItem ("DblI-1", Math.PI);

[XmlRoot ("DoubleItem")]
public class DoubleItem : SerializeDerivedClass.DataItem
{
public DoubleItem(){}
public DoubleItem (string name, double doubleValue) : base (name)
{
_doubleValue = doubleValue;
}

private double _doubleValue;

[XmlAttribute ("DoubleValue")]
public double DoubleValue
{
get { return _doubleValue; }
set { _doubleValue = value; }
}
}

This should produce

<DataRecord>
<DataItem Name="DI-1" />
<IntItem Name="II-1" IntValue="3" />
<DoubleItem Name="DblI-1" DoubleValue="3.1415.."/>
</DataRecord>

Can this behavior be achieved without rebuilding the first class library CL1?
Why 'DoubleItem' is "not expected" while every instance
of 'DoubleItem' is 'DataItem'?

Aleksei Guzev


Nov 12 '05 #2

P: n/a
Thanks. This is just what I was looking for.

On Fri, 26 Nov 2004 20:30:42 -0600, Christoph Schittko [MVP]
<IN**********@austin.rr.com> wrote:
Are you instantiating the XmlSerializer in CL1 or CL2?

I am instantiating the serializer in the third module,
which is using both libraries. It knows DoubleItem unlike CL1.
XmlSerializer xser = new XmlSerializer (typeof (DataRecord), overrides,
new Type[0], null, "" );

If a class is referred in the overrides then it does not need to be
specified
in extraTypes to the serializer constructor.
At first, I've thought "new Type [0]" was an error in Your code ;)
Notice here the attributes in the XmlAttributeOverrides collection
override all attributes in the original class. They are not added, to
the existing ones. You have to add the attributes for the DataItem and
IntItem types again, too.


But attributes applied to the fields of DataItem etc remain.

Thank You very much.

Aleksei Guzev
Nov 12 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.