0

我为我的 WP7 应用程序提交了更新,我有用户抱怨他们的数据在更新后被删除了。我通过将 ViewModel 类序列化为 IsolatedStorage 中的 XML 文件来存储数据。在我的测试过程中,我注意到更新应用程序导致设置文件被我的 ViewModel 对象的新实例(具有默认值)的序列化副本部分覆盖。我以为我在写入 XML 文件时使用 FileMode.Create 解决了这个问题,但我猜不是。

序列化是否会出错,因为我向 ViewModel 对象添加了新属性并且从现有 XML 文件反序列化失败?如果无法从 XML 文件中读取一个新的 ViewModel 对象,我确实将我的代码设置为实例化一个新的 ViewModel 对象。如果是这种情况,是否意味着我无法向 ViewModel 对象添加任何新属性?

编辑:
这是我的 ViewModel 的结构,并不是那么复杂:

public class MyClass: INotifyPropertyChanged
{
    public MyClass()
    {
        // Set defaults
        this.Items= new ObservableCollection<Item>();
        this.TextTemplate = "default";
        this.HasSeenSomething = false;
    }

    public ObservableCollection<Item> Items { get; set; }
    // New properties added in app update
    public string TextTemplate { get; set; }
    public bool HasSeenSomething { get; set; }
}

这是我用来序列化/反序列化我的 ViewModel 的代码。我认为这是非常标准的,但也许我搞砸了一些事情:

public static void WriteToXml<T>(T data, string path)
{
    var xmlWriterSettings = new XmlWriterSettings { Indent = true };
    using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Create))
        {
            var serializer = new XmlSerializer(typeof(T));
            using (var xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
            {
                serializer.Serialize(xmlWriter, data);
            }
        }
    }
}

public static T ReadFromXml<T>(string path)
{
    T data = default(T);
    try
    {
        using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (myIsolatedStorage.FileExists(path))
            {
                using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Open))
                {
                    try
                    {
                        var serializer = new XmlSerializer(typeof(T));
                        object instance = serializer.Deserialize(stream);
                        if (instance != null) data = (T)instance;
                    }
                    catch (System.Exception ex)
                    {
                        var e = ex;
                    }
                }
            }
        }
    }
    catch(System.Exception ex) 
    {
        var e = ex;
    }
    return data;
}
4

1 回答 1

0

你可以,但有一些陷阱。

  1. 您需要确保不会以在反序列化时会中断的方式更改属性。因此,将 Int 更改为 String 是可以的(尽管我不建议这样做),但相反的情况可能会中断。
  2. 您需要记住,反序列化对象时不会调用 ctor。这意味着,如果您在 ctor 中执行以下操作:

    公共 MyClass() { MyV2Collection = new Collection(); }

如果集合为空,您没有其他机制可以更新集合,您将在第一次尝试访问该属性时死于 NullRef。

一角钱兑美元,我敢打赌你正在打 pt #2。

修复它相当容易,但你需要记住去做。选项包括:

  1. 在属性访问器中,检查支持字段是否为空,如果是则实例化它。
  2. 创建一个具有装饰它的属性的函数 ( public) 。[OnDeserialized]该代码将在反序列化完成后运行,您可以在那里实例化您的成员。
于 2012-04-04T22:38:48.277 回答