Serializing a List<Interface> Property

  • Thread starter Thread starter Roman
  • Start date Start date
R

Roman

Hi there,

I was trying to serialize an object with a List<Interface> as
property. If I do this i get an exception. when I add an extra proerty
with type object[] to my class and mark the original property with
[XmlIgnore] it works.
Is there a bettert way to do this without adding this property?

Thanks in advance
Roman

Code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.Xml;

namespace SerializeTest
{
public class Program
{
static void Main(string[] args)
{
// Create objects
MainClass cm = new MainClass();

cm.TestList.Add(new Test1());

// Try to serialize MainClass
XmlTextWriter writer = new XmlTextWriter(Console.Out);

XmlSerializer ser = new XmlSerializer(typeof(MainClass), new Type
[]{typeof(Test1)});
ser.Serialize(writer, cm);

Console.ReadLine();

}
}

[Serializable]
public class MainClass
{
private List<ITest> _test = new List<ITest>();

public object[] TestListO
{
get
{
return (object[])_test.ToArray();
}
set
{
foreach (object o in value)
{
if (o is ITest
&& !_test.Contains((ITest)o))
{
_test.Add((ITest)o);
}
}
}
}

[XmlIgnore]
public List<ITest> TestList
{
get { return _test; }
set { _test = value; }
}
}

[Serializable]
public class Test1 : ITest
{

#region ITest Members

public void Test()
{
Console.WriteLine(this.GetType().Name);
}

#endregion
}


public interface ITest
{
void Test();
}
}
 
Roman said:
I just found exactly the same issue adressed years before:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94530

Is there a solution since then?

XML serialization is basically ossified, superseded by WCF's DataContract
serialization and the LINQ to XML classes (which allow for easy XML
generation). It is what it is now, and it's unlikely to ever change.

Your options are either to not use an interface but an abstract class, to
continue using the workaround specified in the post (to provide a separate
property for the XmlSerializer only) or to customize serialization
completely by implementing IXmlSerializable. The latter is a lot of work and
basically destroys the only advantage XML serialization has left: that it's
easy to use.

Another option is to move away from XML serialization altogether. When it
works it's quick and easy, but when it doesn't work the workarounds are more
trouble than the alternatives. If you're using .NET 3.5, use either data
contracts if you don't need to produce arbitrary XML (attributes are only
possible indirectly by serializing XElement or XmlElement fields, for
example) or XElement if you do. If you're stuck with .NET 2.0, you'll have
to decide for yourself whether you can live with the workarounds or use
XmlWriter/XmlDocument directly.

Incidentally, your use of the [Serializable] attribute on your classes has
no effect on XML serialization at all. This attribute is only used by the
binary serializer (used in remoting). The binary serializer, in turn,
ignores the XML serialization attributes (for example, you need
[NonSerialized] rather than [XmlIgnore] to make the binary serializer ignore
a field). There's nothing wrong with it, by the way (and for all I know
these classes need to have binary serialization as well) but it's worth
pointing out.
 
Jeroen, thanks for the answer. I can live with my workaround with the
knowledge that there is no 'elegant' soluton.

The attribute [NonSerialized] is only applicable on field declarations
and not for properties. For me there is no need to change.

Thanks
Roman
 
I was just playing around with the suggested DataContractSerializer
from WCF.

Is it true that I have to make private members public in order to get
them serialized?

Thanks in advance
Roman
 
I question the notion that interfaces should be serializable/deserializable.
The point is that when an object is deserialized, it has to be reconstructed
from the serialized data (whether its XML or anything else). Interfaces, by
definition, do not have constructors. During deserialization, there no way
to determine how to hydrate the object.
 
XML Serialization has always included only public members.

My impression is that WCF is not a replacement for XML Serialization but
rather a framework for creating classes that are usable in different
operating envirouments. Attributes like <DataContract> and
<OperationContract> cause an object to be (in effect) serialzed differently
in different environments. By default, the classes created by WCF are Web
Methods that rely on XML Serialization.

So, where the coding practices with WCF are different, I would not expect
significantly different behavior in how it serializes and deserializes
objects to XML.

Back to your original issue:

I've done this type of this thing before. Maybe this helps (or maybe you
already got this far anyway)...

public Test[] Tests
{
get { return _testList.ToArray() }
set { tList = value.ToList(); }
}

IList<Test> testList;

Your resulting serialized data is an array named "Tests" with a series of
nested elements named "Test", or whatever you might want to re-name with
attributes, etc. But Test has to be a concrete class. This, admittedly,
only party addresses your issue.
 
Rich said:
I question the notion that interfaces should be serializable/deserializable.
The point is that when an object is deserialized, it has to be reconstructed
from the serialized data (whether its XML or anything else). Interfaces, by
definition, do not have constructors. During deserialization, there no way
to determine how to hydrate the object.

If you don't serialize the object type as well, indeed there is not. And XML
serialization happens not to do that by default, so yeah. You hit the same
problem if you're using inheritance.

With binary serialization, for example, there is no problem serializing and
deserializing object references that happen to be stored as interface
references, because binary serialization always takes the concrete type into
account. The only way to do that in XML serialization is by implementing
IXmlSerializable and using your own schema to determine the actual type to
instantiate.
 
Roman said:
I was just playing around with the suggested DataContractSerializer
from WCF.

Is it true that I have to make private members public in order to get
them serialized?
No. Data contract serialization operates only on members explicitly marked
[DataMember]. The visibility of the member is irrelevant, and it works on
both fields and properties.
 
Rich said:
My impression is that WCF is not a replacement for XML Serialization
but rather a framework for creating classes that are usable in different
operating envirouments. Attributes like <DataContract> and
<OperationContract> cause an object to be (in effect) serialzed
differently in different environments. By default, the classes created by
WCF are Web Methods that rely on XML Serialization.
We have to be careful here.

"XML serialization" is a name for a specific technology in the .NET
Framework that involves the use of the XmlSerializer class.

WCF is a framework for service applications. WCF includes data contract
serialization, which involves the use of the DataContractSerializer class.

Both of these technologies can be used to serialize objects to XML, but they
are radically different in approach. Furthermore, you can use data contract
serialization without involving any of the other features of WCF. WCF can
actually use XML serialization for backward compatibility, but it is not the
default.
So, where the coding practices with WCF are different, I would not expect
significantly different behavior in how it serializes and deserializes
objects to XML.
Data contract serialization to XML and XML serialization differ a great
deal. The biggest difference is that data contract serialization is opt-in
and gives you far less freedom in determining the output format of your XML.
On the flip side, data contract serialization can serialize practically
anything, where XML serialization has some annoying restrictions that can
only be overcome by ugly hacks that expose internals or by writing the
serialization code yourself, which defeats the purpose.
 
Back
Top