9

我曾经用 BinaryFormatter (c#) 序列化树视图。执行此操作并包含所有可序列化类的程序集现在具有强名称并已签名并且还获得了新版本号(但是,实现没有改变)。

当我尝试反序列化 byte[] 数组时,该行

(TreeViewData)binaryFormatter.Deserialize(memoryStream);

产生 ArgumentNullException。(参数名称:类型)

我以为是版本号的问题,所以我实现了一个自己的Binder。我覆盖了 BindToType 方法并确保版本已更正并返回正确的类型。

但是,在程序离开 BindToType 方法的那一刻,我仍然得到上面提到的异常。

我该如何解决?

4

3 回答 3

12

您可以使用 aSerializationBinder来解决此问题:

private class WeakToStrongNameUpgradeBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        try 
        {
            //Get the name of the assembly, ignoring versions and public keys.
            string shortAssemblyName = assemblyName.Split(',')[0];
            var assembly = Assembly.Load(shortAssemblyName);
            var type = assembly.GetType(typeName);
            return type;
        }
        catch (Exception)
        {
            //Revert to default binding behaviour.
            return null;
        }
    }
}

然后

var formatter = new BinaryFormatter();
formatter.Binder = new WeakToStrongNameUpgradeBinder();

瞧,您的旧序列化对象可以使用此格式化程序反序列化。如果类型也发生了变化,您可以使用 aSerializationSurrogate将旧类型反序列化为新类型。

正如其他人所提到的,进行自己的序列化而不是依赖IFormatter是一个好主意,因为您可以更好地控制版本控制和序列化大小。

于 2009-11-10T16:08:54.033 回答
3

您可以尝试使用序列化代理,但是如果没有我们可以重现的东西,就很难给出一个像样的答案。

然而,根本问题是 BinaryFormatter 在涉及程序集之类的东西时非常非常脆弱。哎呀,即使在组装中它也足够脆弱。

听起来像是TreeViewData基于树的,所以我想知道 xml 是否会是一个更好的(即更多的版本容忍)选项。如果效率是一个问题,有自定义二进制格式(如protobuf-net)提供高性能、版本容错、可移植二进制序列化。如果您的数据已经序列化...我想知道是否是时候改变轨道了?尝试使用旧程序集反序列化数据,并切换到更健壮的序列化策略。

于 2009-04-23T08:23:58.407 回答
1

我的建议是永远不要将内置序列化用于持久存储。如果将来某天出于其他原因您需要从另一种语言读取和写入文件格式,请始终编写自己的代码。

于 2009-11-10T16:14:16.840 回答