我有以下xml代表两种类型的插件,FilePlugin和RegsitryPlugin:
<Client>
<Plugin Type="FilePlugin">
<Message>i am a file plugin</Message>
<Path>c:\</Path>
</Plugin>
<Plugin Type="RegsitryPlugin">
<Message>i am a registry plugin</Message>
<Key>HKLM\Software\Microsoft</Key>
<Name>Version</Name>
<Value>3.5</Value>
</Plugin>
</Client>
我想将xml反序列化为对象。 正如您所看到的,'Message'元素正在为FilePlugin和RegistryPlugin重复,我正在使用继承:
abstract class Plugin
{
private string _message;
protected Plugin(MISSING conf)
{
// here i need to set my private members like:
// Message = MISSING.Message;
}
}
class FilePlugin : Plugin
{
private string _path;
public FilePlugin(MISSING config)
: base(config)
{
// Here i need to set my private members like:
// _path = config.Path;
}
}
class RegistryPlugin : Plugin
{
private string _key;
private string _name;
private string _value;
public RegistryPlugin(MISSING config)
: base(config)
{
// Here i need to set my private members like:
// _key = config.Key;
// _key = config.Name;
// _key = config.Value;
}
}
}
我需要以某种方式反序列化xml,而不是根据PluginType元素来决定创建哪个实例: 即: 如果它在xml中写入Type = FilePlugin而不是我需要创建
Plugin p1 = new FilePlugin(conf);
如果它在xml中写入Type = RegistryPlugin而不是我需要创建
Plugin p2 = new RegistryPlugin(conf);
请在我的代码中关注我的评论,以了解缺失的部分。 感谢
答案 0 :(得分:4)
创建自己的反序列化器并不难。以下是我的解决方案:
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Xml.Linq;
using System.Reflection;
using System.Text;
namespace WindowsFormsApplication1
{
public abstract class Plugin
{
public string Type { get; set; }
public string Message { get; set; }
}
public class FilePlugin : Plugin
{
public string Path { get; set; }
}
public class RegsitryPlugin : Plugin
{
public string Key { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
static class MyProgram
{
[STAThread]
static void Main(string[] args)
{
string xmlstr =@"
<Client>
<Plugin Type=""FilePlugin"">
<Message>i am a file plugin</Message>
<Path>c:\</Path>
</Plugin>
<Plugin Type=""RegsitryPlugin"">
<Message>i am a registry plugin</Message>
<Key>HKLM\Software\Microsoft</Key>
<Name>Version</Name>
<Value>3.5</Value>
</Plugin>
</Client>
";
Assembly asm = Assembly.GetExecutingAssembly();
XDocument xDoc = XDocument.Load(new StringReader(xmlstr));
Plugin[] plugins = xDoc.Descendants("Plugin")
.Select(plugin =>
{
string typeName = plugin.Attribute("Type").Value;
var type = asm.GetTypes().Where(t => t.Name == typeName).First();
Plugin p = Activator.CreateInstance(type) as Plugin;
p.Type = typeName;
foreach (var prop in plugin.Descendants())
{
type.GetProperty(prop.Name.LocalName).SetValue(p, prop.Value, null);
}
return p;
}).ToArray();
//
//"plugins" ready to use
//
}
}
}
答案 1 :(得分:0)
我的想法:
答案 2 :(得分:0)
您可以使用所谓的“纪念品模式”。
这个想法是你有一些额外的对象,尤其是序列化 - 反序列化。
所以你可能有类似的东西:
public class PluginMemento {
[XmlAttribute] public string Type { get; set; }
[XmlElement] public string Name { get; set; }
[XmlElement] public string Message { get; set; }
[XmlElement] public string Key { get; set; }
..... //all the other properties
}
[XmlRootAttribute("Client")]
public class Client {
[XmlElementAttribute("Plugin")]
public PluginMemento[] plugins;
}
现在,您应该能够将Xml反序列化为客户端类型。
然后,您可以枚举插件,并通过将PluginMemento传递给Type属性中指定的类的构造函数,开始基于PluginMemento.Type属性(通过反射,或使用工厂或工厂方法)创建实例。 / p>
工厂方法非常简单:
public static Plugin CreatePlugin(PluginMemento memento) {
switch(memento.Type) {
case "FirstPlugin": return FirstPlugin(memento);
case "SecondPlugin": return SecongPlugin(memento);
}
}
反思可能更智能,更有趣,但需要更多编码。
答案 3 :(得分:-1)
我会用一个Class来实现Factory Pattern,它会为你生成具体的插件。