自定义对象是可序列化的,但不可反序列化

时间:2013-03-19 13:38:20

标签: c# xml-serialization

通过为实例调用自己的静态函数,我得到了一个具有某些属性的类的对象。如果存在XML文件,则该对象尝试加载它并将其值添加到实例本身。然后,如果XML文件中缺少选项,它将再次保存XML。

我创建了一个小型控制台应用程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;
using System.Xml;

namespace Test
{
    public class Program
    {
        static void Main(string[] args)
        {
            TaskServerSettings s = TaskServerSettings.LoadNew();
        }
    }

    public class TaskServerSettings : IEqualityComparer
    {
        #region SETTINGS PROPERTIES

        public bool Enabled { get; set; }
        public int CheckInterval { get; set; }

        #endregion

        #region CONSTRUCTORS AND METHODS

        public TaskServerSettings()
        {
            this.init();
        }

        public TaskServerSettings(string settingsFile)
        {
            this.init();
            if (settingsFile != null)
            {
                if (File.Exists(settingsFile))
                {
                    this.Load(settingsFile);
                }
                this.Save(settingsFile);
                }
        }

        private void init()
        {
            this.Enabled = true;
            this.CheckInterval = 5000;
        }

        public void Absorb(TaskServerSettings newSettings)
        {
            this.Enabled = newSettings.Enabled;
            this.CheckInterval = newSettings.CheckInterval;
        }

        public static TaskServerSettings LoadNew(string settingsFile = null)
        {
            if (settingsFile == null)
            {
                settingsFile = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.TrimEnd('\\')) + @"\TaskServerSettings.xml";
            }

            return new TaskServerSettings(settingsFile);
        }

        public bool Load(string settingsFile = null)
        {
            if (settingsFile == null)
            {
                settingsFile = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.TrimEnd('\\')) + @"\TaskServerSettings.xml";
            }

            if (!File.Exists(settingsFile))
            {
                throw new FileNotFoundException("Could not find \"" + settingsFile + "\" to load settings.");
            }

            bool result = false;
            using (FileStream fs = new FileStream(settingsFile, FileMode.Open))
            {
                XmlSerializer xs = new XmlSerializer(this.GetType());
                if (!xs.CanDeserialize(XmlReader.Create(fs)))
                {
                    throw new XmlException("\"" + settingsFile + "\" does not have a valid TaskServerSettings XML structure.");
                }
                //try
                //{            // +- InvalidOperationException - Error in XML document (0,0).
                               // v  The root element is missing.
                    this.Absorb(xs.Deserialize(fs) as TaskServerSettings);
                    result = true;
                //}
                //catch { }
            }

            return result;
        }

        public bool Save(string settingsFile = null)
        {
            if (settingsFile == null)
            {
                settingsFile = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.TrimEnd('\\')) + @"\TaskServerSettings.xml";
            }

            bool result = false;
            using (FileStream fs = new FileStream(settingsFile, FileMode.Create))
            {
                XmlSerializer xs = new XmlSerializer(this.GetType());
                try
                {
                    xs.Serialize(fs, this);
                    result = true;
                }
                catch { }
            }

            return result;
        }

        #endregion

        public bool Equals(TaskServerSettings settingsToCompare)
        {
            if (this.Enabled != settingsToCompare.Enabled ||
                this.CheckInterval != settingsToCompare.CheckInterval)
            {
                return false;
            }
            return true;
        }
        bool IEqualityComparer.Equals(object x, object y)
        {
            return x.Equals(y);
        }
        int IEqualityComparer.GetHashCode(object obj)
        {
            throw new NotSupportedException();
        }
    }
}

在第一次运行中使用默认属性值编写对象非常有用。 XML文件如下所示:

<?xml version="1.0"?>
<TaskServerSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Enabled>true</Enabled>
  <CheckInterval>5000</CheckInterval>
</TaskServerSettings>

但是,在第二次运行时反序列化同一文件会在尝试加载文件时导致错误 xs.Deserialize(fs) as TaskServerSettings

InvalidOperationException - Error in XML document (0,0).
The root element is missing.

我已经尝试避免静态方法并尝试new以及我已经尝试删除IEqualityComparer父+前三种方法。没有成功。

我想知道,这个错误的原因是什么?

1 个答案:

答案 0 :(得分:3)

执行此声明时:

if (!xs.CanDeserialize(XmlReader.Create(fs)))

它开始阅读流。因此,当您稍后调用Deserialize时,流不在开头,因此反序列化失败。您需要通过设置fs.Position = 0

来回放流