我正在为我的公司开发一个内部项目,项目的一部分是能够将XML文件中的各种"任务"解析为稍后要运行的任务集合.
因为每种类型的Task都有许多不同的相关字段,所以我认为最好用一个单独的类来表示每种类型的Task.
为此,我构建了一个抽象基类:
public abstract class Task { public enum TaskType { // Types of Tasks } public abstract TaskType Type { get; } public abstract LoadFromXml(XmlElement task); public abstract XmlElement CreateXml(XmlDocument currentDoc); }
每个任务都继承自此基类,并包含从传入的XmlElement创建自身所需的代码,以及将自身序列化为XmlElement.
一个基本的例子:
public class MergeTask : Task { public override TaskType Type { get { return TaskType.Merge; } } // Lots of Properties / Methods for this Task public MergeTask (XmlElement elem) { this.LoadFromXml(elem); } public override LoadFromXml(XmlElement task) { // Populates this Task from the Xml. } public override XmlElement CreateXml(XmlDocument currentDoc) { // Serializes this class back to xml. } }
然后,解析器将使用与此类似的代码来创建任务集合:
XmlNode taskNode = parent.SelectNode("tasks"); TaskFactory tf = new TaskFactory(); foreach (XmlNode task in taskNode.ChildNodes) { // Since XmlComments etc will show up if (task is XmlElement) { tasks.Add(tf.CreateTask(task as XmlElement)); } }
所有这些都非常有效,并且允许我使用基类传递任务,同时保留为每个任务创建单独类的结构.
但是,我对TaskFactory.CreateTask的代码不满意.此方法接受XmlElement,然后返回相应Task类的实例:
public Task CreateTask(XmlElement elem) { if (elem != null) { switch(elem.Name) { case "merge": return new MergeTask(elem); default: throw new ArgumentException("Invalid Task"); } } }
因为我必须解析XMLElement,所以我使用了一个巨大的(实际代码中的10-15个案例)开关来选择要实例化的子类.我希望我能在这里做一些多态的技巧来清理这个方法.
有什么建议?
我用反射来做到这一点.您可以创建一个基本上扩展的工厂,而无需添加任何额外的代码.
确保你有"使用System.Reflection",将以下代码放在实例化方法中.
public Task CreateTask(XmlElement elem) { if (elem != null) { try { Assembly a = typeof(Task).Assembly string type = string.Format("{0}.{1}Task",typeof(Task).Namespace,elem.Name); //this is only here, so that if that type doesn't exist, this method //throws an exception Type t = a.GetType(type, true, true); return a.CreateInstance(type, true) as Task; } catch(System.Exception) { throw new ArgumentException("Invalid Task"); } } }
另一个观察结果是,你可以将这个方法设置为静态并将其挂在Task类之外,这样你就不需要新建TaskFactory了,而且你也可以自己保存一个移动的东西来维护.
创建每个类的"Prototype"实例,并将它们放在工厂内的哈希表中,并将XML中的字符串作为键.
所以CreateTask只是通过哈希表中的get()来找到正确的Prototype对象.
然后在上面调用LoadFromXML.
你必须将类预先加载到哈希表中,
如果你想要它更自动......
您可以通过在工厂中调用静态寄存器方法来使类"自行注册".
将调用寄存器(带有构造函数)放在Task子类的静态块中.然后你需要做的就是"提及"类来运行静态块.
然后,任务子类的静态数组就足以"提及"它们.或者使用反射来提及类.