0

我有一个简单的应用程序,我在其中将包含所有配置文件对象的配置文件处理程序序列化到磁盘。它工作得很好……但让我感到震惊的是,将来会有问题。

下次我更新软件时,配置文件可能会发生变化,包括新的字段和属性,或者某些类型可能会发生变化。当尝试从早期版本反序列化时,这当然会破坏程序。

解决这个问题的最简单和最直接的方法是什么?我在想应该有一种方法可以在二进制文件中添加一些标头位,然后以某种方式检查它们。

这是我的序列化方法:

private void SaveProfilesToDisk()
{
    var serializer = new BinaryFormatter();

    string filename = Path.Combine(Environment.CurrentDirectory, @"MyApp\MyApp.profiles");
    using (FileStream fileStream = File.OpenWrite(filename))
    {
        serializer.Serialize(fileStream, _profileHandler);
    }
}

这就是我反序列化它的方式:

 private ProfileHandler LoadProfilesFromDisk()
    {
        var serializer = new BinaryFormatter();

        string filename = Path.Combine(Environment.CurrentDirectory, @"MyApp\MyApp.profiles");
        using (FileStream fileStream = File.OpenRead(filename))
        {
            return (ProfileHandler) serializer.Deserialize(fileStream);
        }
    }

我可以简单地告诉用户保存文件已过时,重命名/删除它并创建一个新文件。

4

1 回答 1

1

编辑: 在重新阅读问题时,我意识到值得一提的是,AssemblyResolve 事件将收到反序列化器试图解析的程序集版本。如果您想要的只是不兼容的版本消息,您可以捕获程序集名称是您的程序集名称并且版本与当前版本不同并相应提示的位置。

我同意@smoore 的观点,最简单的方法是使用 XmlSerialization,因为它能够反序列化发生非破坏性更改的先前版本的配置文件。XmlSerializer 将简单地忽略不存在的字段,并愉快地反序列化存在的字段。

如果您出于某种原因确实需要二进制序列化,并且如果应用程序可以使用旧版本的对象,那么执行此操作的一种方法是不关心反序列化的版本,而只是尝试匹配和反序列化任何内容属性是可能的。对于非破坏性更改,例如添加新属性,您应该能够毫无问题地反序列化旧版本。

首先注册类型解析事件:

AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

接下来添加您的类型解析方法,并为您感兴趣的程序集返回这些程序集的当前版本。这是一个例子,我做了这样的事情:

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
            Assembly result = null;
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
                AssemblyName assemblyName = assembly.GetName();
                if (args.Name.StartsWith(assemblyName.Name)) {
                    this.LogInfo("Assembly \"" + args.Name + "\" resolved to \"" + assembly.Location + "\".");
                    result = assembly;
                    break;
                }
            }
            if(result != null){
                return result;
            }else{
                this.LogError("Assembly resolution failure. An assembly named \"" + args.Name + "\" was not found.");
                return null;
            }
        }

如果我的想法正确,这应该将类型解析为新版本,并允许您反序列化发生非破坏性更改的旧版本。对于中断更改,最简单的方法是捕获 SerializationException 并相应地提示用户。

于 2013-06-25T16:15:47.700 回答