XmlIncludeAttribute puts the cart before the horse.

B

Bill Ward

I have a problem with XML serialization to files that seems to stem from
someone putting the cart before the horse. I have "Jobs" that include a
series of "Actions". An Action is defined as an abstract class that has a
series of specialized concrete classes derived from it. A Job defines a list
of actions (amongst other things). The concrete action classes are what
actually get serialized in files as a part of the Job.

In order for the XmlSerializer class to recognize the derived classes and to
not throw an InvalidOperationException, the Job class needs to be tagged
with the XmlIncludeAttribute for every Action-derived class that I may want
to serialize. In other words, it needs knowledge of all classes I may want
to derive now and in the future. (Read "recompile and retest whenever I or
another developer wants to extend my framework"). At runtime I would like to
be able to use reflection to snoop yet to be defined DLLs and add their
Action derived concrete classes to the list of types supported. The question
is how is this done?

Thanks in advance.

Bill



using System;

using System.Collections.Generic;

using System.Text;

using System.Xml.Serialization;

using System.IO;

namespace XmlSerializationProblem

{

public abstract class Action

{

public string InAll

{

get { return "AnAll"; }

set { System.Diagnostics.Debug.Assert(InAll == value); }

}

}

public class ActionSpecialized1 : Action

{

public string OnlyIn1

{

get { return "OnlyIn1"; }

set { System.Diagnostics.Debug.Assert(OnlyIn1 == value); }

}

}

public class ActionSpecialized2 : Action

{

public string OnlyIn2

{

get { return "ActionSpecialized2"; }

set { System.Diagnostics.Debug.Assert(OnlyIn2 == value); }

}

}

public class ActionSpecialized3 : Action

{

public string OnlyIn3

{

get { return "ActionSpecialized3"; }

set { System.Diagnostics.Debug.Assert(OnlyIn3 == value); }

}

}


[

XmlInclude(typeof(ActionSpecialized1)),

XmlInclude(typeof(ActionSpecialized2))

]

public class Job

{

private List<Action> m_oActions = new List<Action>();

[XmlElement()]

public Action[] Actions

{

get { return m_oActions.ToArray(); }

set

{

m_oActions.Clear();

if (null != value)

{

foreach (Action oAction in value)

m_oActions.Add(oAction);

}

}

}

public void AddAction(Action oAction)

{

m_oActions.Add(oAction);

}

public void Serialize()

{

TextWriter oTextWriter = new StreamWriter(@"TestFile.xml");

XmlSerializer oSerializer = new XmlSerializer(typeof(Job));

// Serialize the job

oSerializer.Serialize(oTextWriter, this);

oTextWriter.Flush();

oTextWriter.Close();

}

public static Job Deserialize()

{

FileStream oFileStream = new FileStream(@"TestFile.xml", FileMode.Open,
FileAccess.Read);

XmlSerializer oSerializer = new XmlSerializer(typeof(Job));

// Deserialize the job

Job oJob = (Job)oSerializer.Deserialize(oFileStream);

oFileStream.Close();

return oJob;

}

}


class Program

{

static void Main(string[] args)

{

Job oJob = new Job();

oJob.AddAction(new ActionSpecialized1());

oJob.AddAction(new ActionSpecialized2());

// oJob.AddAction(new ActionSpecialized3());

oJob.Serialize();

oJob = null;

oJob = Job.Deserialize();

}

}

}
 
B

Bill Ward

Problem solved - use a different constructor for the XmlSerializer object,
the one that takes an array of additional object types. It works
wonderfully.

Bill Ward said:
I have a problem with XML serialization to files that seems to stem from
someone putting the cart before the horse. I have "Jobs" that include a
series of "Actions". An Action is defined as an abstract class that has a
series of specialized concrete classes derived from it. A Job defines a
list of actions (amongst other things). The concrete action classes are
what actually get serialized in files as a part of the Job.

In order for the XmlSerializer class to recognize the derived classes and
to not throw an InvalidOperationException, the Job class needs to be
tagged with the XmlIncludeAttribute for every Action-derived class that I
may want to serialize. In other words, it needs knowledge of all classes I
may want to derive now and in the future. (Read "recompile and retest
whenever I or another developer wants to extend my framework"). At runtime
I would like to be able to use reflection to snoop yet to be defined DLLs
and add their Action derived concrete classes to the list of types
supported. The question is how is this done?

Thanks in advance.

Bill



using System;

using System.Collections.Generic;

using System.Text;

using System.Xml.Serialization;

using System.IO;

namespace XmlSerializationProblem

{

public abstract class Action

{

public string InAll

{

get { return "AnAll"; }

set { System.Diagnostics.Debug.Assert(InAll == value); }

}

}

public class ActionSpecialized1 : Action

{

public string OnlyIn1

{

get { return "OnlyIn1"; }

set { System.Diagnostics.Debug.Assert(OnlyIn1 == value); }

}

}

public class ActionSpecialized2 : Action

{

public string OnlyIn2

{

get { return "ActionSpecialized2"; }

set { System.Diagnostics.Debug.Assert(OnlyIn2 == value); }

}

}

public class ActionSpecialized3 : Action

{

public string OnlyIn3

{

get { return "ActionSpecialized3"; }

set { System.Diagnostics.Debug.Assert(OnlyIn3 == value); }

}

}


[

XmlInclude(typeof(ActionSpecialized1)),

XmlInclude(typeof(ActionSpecialized2))

]

public class Job

{

private List<Action> m_oActions = new List<Action>();

[XmlElement()]

public Action[] Actions

{

get { return m_oActions.ToArray(); }

set

{

m_oActions.Clear();

if (null != value)

{

foreach (Action oAction in value)

m_oActions.Add(oAction);

}

}

}

public void AddAction(Action oAction)

{

m_oActions.Add(oAction);

}

public void Serialize()

{

TextWriter oTextWriter = new StreamWriter(@"TestFile.xml");

XmlSerializer oSerializer = new XmlSerializer(typeof(Job));

// Serialize the job

oSerializer.Serialize(oTextWriter, this);

oTextWriter.Flush();

oTextWriter.Close();

}

public static Job Deserialize()

{

FileStream oFileStream = new FileStream(@"TestFile.xml", FileMode.Open,
FileAccess.Read);

XmlSerializer oSerializer = new XmlSerializer(typeof(Job));

// Deserialize the job

Job oJob = (Job)oSerializer.Deserialize(oFileStream);

oFileStream.Close();

return oJob;

}

}


class Program

{

static void Main(string[] args)

{

Job oJob = new Job();

oJob.AddAction(new ActionSpecialized1());

oJob.AddAction(new ActionSpecialized2());

// oJob.AddAction(new ActionSpecialized3());

oJob.Serialize();

oJob = null;

oJob = Job.Deserialize();

}

}

}
 

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

Similar Threads


Top