将XML正确地反序列化到类中

时间:2012-06-28 13:14:56

标签: c# .net xml serialization

我已经设法从几个类中轻松生成XML文件,如下所示;

public class AllConfig : XMLEncapsulator
{
    [XmlElement("Database-Settings")]
    public DataBaseConfiguration databaseConfiguration { get; set; }
    [XmlElement("Merlin-Settings")]
    public MerlinConfiguration merlinConfiguration { get; set; }
}



public class DataBaseConfiguration : XMLEncapsulator
{
    public string dbIP { get; set; }
    public int ?port { get; set; }
    public string username { get; set; }
    public string password { get; set; }
}

public class MerlinConfiguration : XMLEncapsulator
{
    public string MerlinIP { get; set; }
    public int ?MerlinPort { get; set; }
    public int ?RecievingPort { get; set; }
}


// load classes with information, then;

  try
        {
            allConfig.databaseConfiguration = dbConfig;
            allConfig.merlinConfiguration = merlinConfig;
            allConfig.Save();
        }
        catch (Exception ErrorFinalisingSave)
        {
            MessageBox.Show(ErrorFinalisingSave.Message + "3");
        }

这很有效,并且给了我:

<AllConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <databaseConfiguration>
 <dbIP></dbIP>
 <port></port>
 <username></username>
 <password></password>
</databaseConfiguration>
<merlinConfiguration>
 <MerlinIP></MerlinIP>
 <MerlinPort></MerlinPort>
 <RecievingPort></RecievingPort>
 </merlinConfiguration>
</AllConfig>

但是,我如何将这个检索回到我的表格中?所以我有这样的东西,但我似乎无法让它工作;

  AllConfig allConfig;
    DataBaseConfiguration dbConfig;
    MerlinConfiguration merlinConfig;

  //need to load here.

//check if values loaded are null, and then load them if they exist into textboxes and such.

我应该加载两个配置类,然后将它们分配给整个配置类?或者我是否需要加载整个类并分配子配置类,如此;

 allConfig = new AllConfig();

                dbConfig = new DataBaseConfiguration();
                merlinConfig = new MerlinConfiguration();

                allConfig.databaseConfiguration = dbConfig;
                allConfig.merlinConfiguration = merlinConfig;

                allConfig.databaseConfiguration.Load();
                allConfig.merlinConfiguration.Load();

编辑:继承我的加载方法;

 public virtual void Load()
{
    if (File.Exists(DeviceManager.path))
    {
        StreamReader sr = new StreamReader(DeviceManager.path);
        XmlTextReader xr = new XmlTextReader(sr);
        XmlSerializer xs = new XmlSerializer(this.GetType());
        object c;
        if (xs.CanDeserialize(xr))
        {
            c = xs.Deserialize(xr);
            Type t = this.GetType();
            PropertyInfo[] properties = t.GetProperties();
            foreach (PropertyInfo p in properties)
            {
                p.SetValue(this, p.GetValue(c, null), null);
            }
        }
        xr.Close();
        sr.Close();
    }
}

4 个答案:

答案 0 :(得分:1)

这是一个用于从Xml反序列化对象的通用方法。这有帮助吗?

public static T Deserialize<T>(string xml) where T : class, new()
{
    if (string.IsNullOrEmpty(xml))
    {
        throw new ArgumentNullException("xml");
    }

    return (T)Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(xml)));
}

public static T Deserialize<T>(Stream xmlStream) where T : class, new()
{
    if (xmlStream == null)
    {
        throw new ArgumentNullException("xmlStream");
    }

    return (T)xmlSerializer.Deserialize(xmlStream);
}

答案 1 :(得分:1)

您使用allConfig.Save();保存课程,然后尝试使用

加载
allConfig.databaseConfiguration.Load();
allConfig.merlinConfiguration.Load();

看起来您没有正确使用XmlSerializer。 所以试试这个:

public class Person
{
  public string Name;
  public int Age;
}

p.Name = "Stacey"; p.Age = 30;

//serialize
XmlSerializer xs = new XmlSerializer (typeof (Person));

using (Stream s = File.Create ("person.xml"))
  xs.Serialize (s, p);

//deserialize
Person p2;
using (Stream s = File.OpenRead ("person.xml"))
  p2 = (Person) xs.Deserialize (s);

Console.WriteLine (p2.Name + " " + p2.Age);   // Stacey 30

C# in Nutshell

更新: 在这里,我对您的代码采用示例。我删除XmlEncapsulator因为我认为它实现了Save and Load方法,这并不是真正需要的。如果你真的需要它,你可以退货。不要以为某些事情可能会改变; 所以,这里是代码:

         AllConfig all = new AllConfig();
         all.databaseConfiguration = new DataBaseConfiguration();
         all.databaseConfiguration.dbIP = "123";
         all.databaseConfiguration.password = "asd";
         all.databaseConfiguration.port = 123;
         all.databaseConfiguration.username = "sad";
         all.merlinConfiguration = new MerlinConfiguration();
         all.merlinConfiguration.MerlinIP = "123";
         all.merlinConfiguration.MerlinPort = 123;
         all.merlinConfiguration.RecievingPort = 123;

        //serialize 
        XmlSerializer xs = new XmlSerializer(typeof(AllConfig));
        using (Stream s = File.Create ("config.xml"))
            xs.Serialize (s, all); 
        //deserialize 
        AllConfig all2;  
        using (Stream s = File.OpenRead ("config.xml"))
            all2 = (AllConfig)xs.Deserialize(s);
        Console.WriteLine(all2.ToString());

答案 2 :(得分:1)

以下是我如何使用您的数据类型实现它。正如其他人所说,我只是删除您从中派生数据类型的XMLEncapsulator。另请注意,在生成的xml中,您指定的XmlElement属性现在正在受到尊重。

public void Test()
{
   var dbConfig = new DataBaseConfiguration();
   dbConfig.dbIP = "127.0.0.1";
   dbConfig.port = 12345;
   dbConfig.username = "harlam357";
   dbConfig.password = "password";
   var merlinConfig = new MerlinConfiguration();
   merlinConfig.MerlinIP = "192.168.0.1";
   merlinConfig.MerlinPort = 8080;
   merlinConfig.RecievingPort = 8081;
   var config = new AllConfig { databaseConfiguration = dbConfig, merlinConfiguration = merlinConfig };

   string xml = Serialize(config);
   var config2 = Deserialize<AllConfig>(xml);

   Debug.Assert(config2.databaseConfiguration.dbIP == "127.0.0.1");
   Debug.Assert(config2.databaseConfiguration.port == 12345);
   Debug.Assert(config2.databaseConfiguration.username == "harlam357");
   Debug.Assert(config2.databaseConfiguration.password == "password");
   Debug.Assert(config2.merlinConfiguration.MerlinIP == "192.168.0.1");
   Debug.Assert(config2.merlinConfiguration.MerlinPort == 8080);
   Debug.Assert(config2.merlinConfiguration.RecievingPort == 8081);
}

public static string Serialize<T>(T value) where T : class
{
   if (value == null) return null; // throw or whatever fits your use case

   var xmlSerializer = new XmlSerializer(typeof(T));
   using (var stream = new MemoryStream())
   {
      xmlSerializer.Serialize(stream, value);
      return Encoding.UTF8.GetString(stream.GetBuffer());
   }
}

public static T Deserialize<T>(string xml) where T : class
{
   if (xml == null) return null; // throw or whatever fits your use case

   var xmlSerializer = new XmlSerializer(typeof(T));
   using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
   {
      return (T)xmlSerializer.Deserialize(stream);
   }
}

生成的XML

<?xml version="1.0"?>
<AllConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Database-Settings>
    <dbIP>127.0.0.1</dbIP>
    <port>12345</port>
    <username>harlam357</username>
    <password>password</password>
  </Database-Settings>
  <Merlin-Settings>
    <MerlinIP>192.168.0.1</MerlinIP>
    <MerlinPort>8080</MerlinPort>
    <RecievingPort>8081</RecievingPort>
  </Merlin-Settings>
</AllConfig>

答案 3 :(得分:0)

修复了我自己的问题。这是我加载它的方式,最后我最终这样做了;

allConfig = new AllConfig();
                dbConfig = new DataBaseConfiguration();
                merlinConfig = new MerlinConfiguration();
                allConfig.databaseConfiguration = dbConfig;
                allConfig.merlinConfiguration = merlinConfig;
                allConfig.Load();

所以我创建了一个类序列化的实例,然后创建了包含的类,并将它们分配给主类。然后我加载了主类(我假设通过序列化程序填充它所包含的类,然后我像这样访问它们;

allConfig.databaseConfiguration.port;
allConfig.databaseConfiguration.username;

等等。感谢大家的建议,真的帮助了我。