【问题标题】:deserialising XML correctly into classes将 XML 正确反序列化为类
【发布时间】:2012-06-28 13:14:55
【问题描述】:

我已经设法从几个类轻松生成 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();
    }
}

【问题讨论】:

  • 您是在问如何将 XML 反序列化到您的对象中?
  • 我想是的,是的。编辑:我已经有 .load() 用于加载,我只是不知道加载它们的顺序等等。这有意义吗?
  • 什么是XMLEncapsulator?请向我们展示您用于序列化对象的代码。看起来您并没有直接使用 XmlSerializer。否则,生成的 xml 将具有 Database-SettingsMerlin-Settings 作为元素。
  • @harlam357 查看我的最后编辑:)

标签: c# .net xml serialization


【解决方案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);
}

【讨论】:

    【解决方案2】:

    您正在使用 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 和 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());
    

    【讨论】:

    • 第一个看起来是个好主意,但遗憾的是没有奏效。我会试着看看为什么..
    • 我仍然无法正常工作。从我序列化它的方式来看,我创建了一个整体配置和两个子配置,将子配置分配给整体配置并序列化整体..但我不知道如何以这种方式取回它.. 编辑:可能有刚刚修好了。
    • 感谢您的帮助:) 我使用了您原始答案中的一些来帮助我。在我自己的答案中查看我的解决方案。
    【解决方案3】:

    以下是我将如何使用您的数据类型来实现它。正如其他人所说,我会简单地删除您从中派生数据类型的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>
    

    【讨论】:

    • 感谢您的输入 :) 这只是我坚持的反序列化,但我现在已经修复了!
    【解决方案4】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 2021-07-16
      相关资源
      最近更新 更多