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();
}
}
}
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();
}
}
}