序列化数据的反序列化失败

时间:2015-08-11 16:20:29

标签: c# xml serialization deserialization

我正在尝试反序列化我在另一个时间序列化的XML文档。我用它来存储配置文件。

这是我的代码:

namespace OrderTracker
{
    [Serializable]
    public class AutofillValues
    {
        private string fileName = Directory.GetCurrentDirectory() + "\\bin\\settings.db";

        public ComboBox.ObjectCollection Vendors { get; set; }
        public ComboBox.ObjectCollection Products { get; set; }
        public ComboBox.ObjectCollection Companies { get; set; }

        public void save(AutofillValues afv)
        {
            if (!File.Exists(fileName))
            {
                FileStream fs = File.Create(fileName);
                fs.Close();
            }

            XmlSerializer x = new XmlSerializer(typeof(AutofillValues));
            TextWriter writer = new StreamWriter(fileName);
            x.Serialize(writer, afv);
            writer.Close();
        }

        public AutofillValues load()
        {
            XmlSerializer x = new XmlSerializer(typeof(AutofillValues));
            TextReader file = new StreamReader(fileName);

            AutofillValues av = (AutofillValues)x.Deserialize(file);
            file.Close();
            return av;
        }
    }
}

我在尝试反序列化文件时收到的错误消息是这样的;

  

未处理的类型' System.InvalidOperationException'发生在System.Xml.dll中   附加信息:XML文档中存在错误(2,2)。*

这是XML文档:

<?xml version="1.0" encoding="utf-8"?>
<AutofillValues xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Vendors>
    <anyType xsi:type="xsd:string">Test Vendor</anyType>
  </Vendors>
  <Products>
    <anyType xsi:type="xsd:string">Test Product</anyType>
  </Products>
  <Companies>
    <anyType xsi:type="xsd:string">Test Company</anyType>
  </Companies>
</AutofillValues>

如何反序列化XML文件并取回序列化数据?

2 个答案:

答案 0 :(得分:1)

我刚刚更改了这部分,它对我有用。 JSFiddle Demo

答案 1 :(得分:0)

您无法反序列化XML,因为类ComboBox.ObjectCollection没有标准(无参数)构造函数。这是XmlSerializer类的限制,如此SO post中所述。

然而,当前代码存在另一个问题 - 即使反序列化以某种方式工作,仍然需要将集合分配给ComboBox控件,而解串器仍然无法执行。

我建议不要使用ComboBox.ObjectCollection类来存储项目,而是建议使用对象的数组列表(如@kenlacoste建议的那样) 。可以使用这些集合轻松插入到ComboBox中 comboBox.Items.AddRange(arrayOfObjects)方法。

另一种重构是提取数据类的序列化逻辑。目前,saveload数据令人困惑,因为我认为你想要保存/填充调用者对象:

  • 保存:object.save(object); - 您可以在保存方法中使用this关键字
  • 加载:object = object.load(); - 此处相同,无需返回值,使用this关键字填充现有属性

更改后的代码:

public class AutofillValues
{
    private string fileName = @"d:\settings.db";

    public object[] Vendors { get; set; }
    public object[] Products { get; set; }
    public object[] Companies { get; set; }

    public void save()
    {
        XmlSerializer x = new XmlSerializer(typeof(AutofillValues));
        // with using there is no need to close the writer explicitely
        //  second parameter - file is created if it does not exist
        using (var writer = new StreamWriter(fileName, false))
        {
            x.Serialize(writer, this);
        }
    }

    public void load()
    {
        XmlSerializer x = new XmlSerializer(typeof(AutofillValues));
        AutofillValues av = (AutofillValues)x.Deserialize(new StreamReader(fileName));
        this.Companies = av.Companies;
        this.Vendors = av.Vendors;
        this.Products = av.Products;
    }
}

IMO修改后的代码更易于阅读和理解:

var afv = new AutofillValues();
afv.load();
//use avf.Products
// or afv.save();

我还建议提取需要在额外课程中保存的数据,例如:

[Serializable]
public class AutofillValuesData
{
    public Object[] Vendors { get; set; }
    public Object[] Products { get; set; }
    public Object[] Companies { get; set; }
}

在课程AutofillValues中删除三个属性,只留一个:

public AutofillValuesData Data { get; set; }

然后可以修改逻辑以从填充的数据对象填充ComboBox控件。这样,您的数据就不会硬连线到UI,这将使代码更易于维护。您可以使用AutoMapper之类的帮助程序删除重复代码(例如mappig objA.VendorsobjB.Vendors)。