2012-02-18 71 views
2

我有以下的xml表示2種類型的插件,FilePlugin和RegsitryPlugin的:如何將xml反序列化爲繼承對象?

<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反序列化爲對象。 正如你所看到的,「消息」元素正在重演既爲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類型= FilePlugin比我更需要創造

Plugin p1 = new FilePlugin(conf); 

如果是寫在XML類型= RegistryPlugin比我更需要創造

Plugin p2 = new RegistryPlugin(conf); 

請按照我的意見,在我的代碼,以瞭解缺少的部分。 謝謝

回答

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 [email protected]" 
       <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 
      // 
     } 
    } 
} 
+0

非常好的答案! – user829174 2012-02-18 15:33:06

+0

我有一個關於你的答案的問題,如果我想添加另一個元素到名爲真正的的xml。 Allow屬性可以獲得'True'或'False'的值。我希望後者將其轉換爲Plugin類中的布爾屬性,這意味着該插件將具有:'public bool Allow {get;組; }」。有沒有可能轉換它? – user829174 2012-02-18 15:55:48

-1

我會執行Factory Pattern一個類,它產生你的具體插件。

+0

-1你會得到一個表 - 除非你不知道。並非所有的XML都適合DataSet。 – 2012-02-18 13:18:13

+0

抱歉,錯誤的答案。但對我來說,它總是工作:)。嗯,但爲什麼它不適用於所有的XML? – lhlmgr 2012-02-18 13:55:14

+0

它不適用於無法映射到關係數據庫模型的XML。 – 2012-02-18 18:45:45

0

我的想法:

  • 添加方法和toxml用於向FromXml插件,並允許在插件加載此方法實施方案/只保存像信息在你的榜樣公共屬性;
  • 在派生類中重寫這些方法,並調用基本方法以覆蓋常用參數,以及添加自定義代碼以加載特定參數。
  • 在Plugin中的LoadXml中創建靜態方法,該方法讀取XML文件,獲取類型名稱,使用反射動態創建此類型實例並調用其FromXml方法。
+0

可以請你展示一小段代碼嗎? – user829174 2012-02-18 13:20:34

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屬性(通過反射或使用工廠或工廠方法)創建實例。

工廠方法可以很簡單:

public static Plugin CreatePlugin(PluginMemento memento) { 
    switch(memento.Type) { 
     case "FirstPlugin": return FirstPlugin(memento); 
     case "SecondPlugin": return SecongPlugin(memento); 
    } 
} 

思考可能會更聰明和有趣,但需要多一點的編碼。

+0

如果您只有事先知道的有限的可能類型,您爲什麼需要反思? – svick 2012-02-18 13:28:50

+0

老實說,我現在不是。有些人更喜歡「當你需要解決問題,即使技術更難解決」。特別是在插件方面:未來可能會有更多,或者您可能希望將其擴展。我們不知道這裏的要求。而我並沒有「規定」反思,我只是表現出了不同的做法。我不能決定哪一個是合適的。 – 2012-02-18 13:32:41

+0

謝謝你的回答,但如果我目前明白,所有的屬性將不得不在PluginMemento類,FilePlugin,RegistryPlugin和所有其他插件,我會做...不?我更喜歡將這些屬性分成它們的派生類,有什麼建議嗎? – user829174 2012-02-18 13:51:05