views:

377

answers:

1

Hi,

I have an object InputFile that has arrays and objects to hold the contents of a file. I also have ABCFile and XYZFile that are both inherited from InputFile that will read different types of file and store them into the projected members of InputFile.

Since the serialization and deserialization of both of these objects are identical to the parent object, I have implemented a standard XML serialization interface on the parent object. During deserialization a few paramters are read, a Read function is called (to load a file), then the deserialization finishes.

The serialization works great, but the deserialization (of List<InputFile>) doesn't work because the deserializer calls the parents stub Read file function instead of ABCFile or XYZFile's.

How can I get the deserialization to recognize the correct type of object to use? It is possible that my List<InputFile> will have a mix of file types.

Thanks

The code I use to serialize the object:

public class InputFileHolder : IXmlSerializable {
...
public void WriteXml(XmlWriter w) {
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("", "");

    XmlSerializer ifXml = new XmlSerializer(typeof(List<InputFile>));
    ifXml.Serialize(w, InputFiles, ns);

    //More serialization
}

Any ideas how to maintain the object type when I custom serialize the List?

+1  A: 

Try

[XmlArray]
[XmlArrayItem(ElementName="ABCFile", Type=typeof(ABCFile))]
[XmlArrayItem(ElementName="XYZFile", Type=typeof(XYZFile))]
public List<InputFile> InputFileList
{
   get;
   set;
}

This will indicate the serializer that, even though this is a List of InputFile, there will be two derived types that will be stored in this list. It's likely to make it use specific version of methods for each one.

If it fail, let me know.

Edit based on your comment

I don't see how this can be happing.

I tested it the following classes:

public class InputFile
{
    public String InputfileCommonProperty { get; set; }
}

public class ABCFile : InputFile
{
    public String ABCSpecificProperty { get; set; }
}

public class XYZFile : InputFile
{
    public String XYZSpecificProperty { get; set; }
}

public class InputFileHolder
{
    public InputFileHolder()
    {
        InputFileList = new List<InputFile>();
    }

    [XmlArray]
    [XmlArrayItem(ElementName = "ABCFile", Type = typeof(ABCFile))]
    [XmlArrayItem(ElementName = "XYZFile", Type = typeof(XYZFile))]
    public List<InputFile> InputFileList { get; set; }
}

My main program looks like:

static void Main(string[] args)
{
    InputFileHolder fileHolder = new InputFileHolder();
    fileHolder.InputFileList.Add(
        new ABCFile()
        {
            InputfileCommonProperty = "This is a common property",
            ABCSpecificProperty = "This is a class specific property"
        });

    XmlSerializer serializer = new XmlSerializer(typeof(InputFileHolder));
    MemoryStream memoryStream = new MemoryStream();
    serializer.Serialize(memoryStream, fileHolder);

    System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
    String serializedString = enc.GetString(memoryStream.ToArray());
}

And in the end, serializedString's content is:

<?xml version="1.0"?>
<InputFileHolder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <InputFileList>
    <ABCFile>
      <InputfileCommonProperty>This is a common property</InputfileCommonProperty>
      <ABCSpecificProperty>This is a class specific property</ABCSpecificProperty>
    </ABCFile>
  </InputFileList>
</InputFileHolder>

You see? The serializer knows it's a ABCFile not a generic InputFile.

Ciwee
Thank you for the quick response.The XML generated still looks like: <ArrayOfInputFile><InputFile ...><InputFile ...></ArrayOfInputFile>. If I manually edit the XML to change InputFile to ABCFile it fails with bad XML error.
Aaron
Take a look at my code snippet and tell me what happens
Ciwee
Ok, It think I've discovered the root of the problem. My version of InputFileHolder has an IXmlSerializable interface where I have custom read/write of the parameters to serialize. If I remove the IXmlSerializable interface and let the framework handle it, I get XML like yours, where the object type is specified. I need to have a custom read, so I need to fix the write.I'll add my write code in the main post.
Aaron