C# 在执行二进制反序列化之前检查应用程序版本

C# 在执行二进制反序列化之前检查应用程序版本,c#,.net,serialization,visual-studio-2012,C#,.net,Serialization,Visual Studio 2012,我有一个简单的应用程序,其中我将配置文件处理程序与其中的所有配置文件对象序列化到磁盘。它工作得很好。。。但我突然想到,将来会有问题 下次我更新软件时,配置文件可能会有更改,带有新的字段和属性,或者某些类型可能已更改。当尝试从早期版本反序列化时,这当然会中断程序 解决这个问题最简单、最直接的方法是什么?我认为应该有一种方法可以在二进制文件中添加一些头位,然后以某种方式检查它们 以下是我的序列化程序方法: private void SaveProfilesToDisk() { var ser

我有一个简单的应用程序,其中我将配置文件处理程序与其中的所有配置文件对象序列化到磁盘。它工作得很好。。。但我突然想到,将来会有问题

下次我更新软件时,配置文件可能会有更改,带有新的字段和属性,或者某些类型可能已更改。当尝试从早期版本反序列化时,这当然会中断程序

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

以下是我的序列化程序方法:

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);
        }
    }
我可以简单地告诉用户保存的文件已经过时,重命名/删除它并创建一个新文件

编辑:重读这个问题时,我意识到值得注意的是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并相应地提示用户。

它需要二进制格式,还是xml格式?实际上,不是这样。我希望能够用一个二进制保存文件来解决这个问题,因为它看起来更好一点,但是XML将是一个更简单的解决方案。谢谢。我要深入研究一下。这比我现在的水平高了一点,但很有教育意义。谢谢。目前我只是捕获SerializationException,告诉用户删除坏文件,然后我返回一个新的ProfileHandler对象,而不是反序列化的对象。但我会彻底调查你的解决方案。