【问题标题】:.NET 4.5 MethodInfo serialization breaking change.NET 4.5 MethodInfo 序列化重大更改
【发布时间】:2013-01-07 15:15:14
【问题描述】:

问题

使用 1.0 版本的程序集序列化的对象(具有私有 MethodInfo 字段)不会使用该程序集的 1.1 版本反序列化(将抛出 SerializationException,因为未找到所需的方法)。

发生了什么变化?

我发现在 .NET 4.5 中,MemberInfo 通过MemberInfoSerializationHolder 的序列化机制已经改变。在过去(直到 .NET 4.0),序列化数据是方法签名(通过简单的MethodInfo.ToString() 获得)。 根据 .NET 源代码中的 cmets,他们添加了通过 SerializationToString() 获得的第二个签名,因为:

m_signature 存储有时不明确的成员的 ToString() 表示。相同方法或属性的多个重载可以相同 ToString()。 m_signature2 存储对每个成员来说应该是唯一的 SerializationToString() 表示。它仅由 4.0 后的 CLR 版本编写和使用。

对于我所看到的,MemberInfoSerializationHolder.GetRealObject() 使用此(简化)代码来解析方法(来自 .NET 源代码):

for (int i = 0; i < methods.Length; i++)
{ 
    if (m_signature2 != null) // SerializationToString() signature
    {
        if (((RuntimeMethodInfo)methods[i]).SerializationToString().Equals(m_signature2))
        { 
            methodInfo = methods[i];
            break; 
        } 
    }
    else 
    {
        if (methods[i].ToString().Equals(m_signature))
        { 
            methodInfo = methods[i];
            break; 
        }
    }
}

if (methodInfo == null)
    throw new SerializationException(...);

在这种情况下,反序列化失败,因为找不到 m_signature2 签名,因为程序集名称包含版本信息,然后 String.Equals() 将无法匹配 MyAssembly, Version=1.0.0.0MyAssembly, Version=1.1.0.0,并且将引发异常。

问题

如果 new 搜索失败(至少因为与现有代码的兼容性),我希望框架将失败返回到 old 搜索方法。我不明白为什么要与String.Equals() 进行比较,在运行时解析所有版本的程序集之后(默认情况下将加载新版本),我同意它无法解析程序集版本但如果 strict 搜索失败,它可能会删除/忽略它。

我知道序列化 MethodInfo 很糟糕,但此时此修复可能涉及太多更改(包括架构和代码),没有人会在旧代码中开始重构(此外,存档的二进制兼容性必须是为新旧版本保留,双向)。

到目前为止我还没有尝试过,但是这个问题也适用于代表吗? 是否有任何解决方案(通过属性或少量代码更改)来解决此问题?

【问题讨论】:

    标签: .net serialization .net-4.5


    【解决方案1】:

    我能想到的最好办法就是实现ISerializableMSDN

    在具有MethodInfo 属性的对象上实现此接口可以让您几乎完全控制序列化/反序列化。

    缺点是您还必须以某种通用方式处理所有其他属性。不过应该是可行的。

    【讨论】:

    • 我同意它可以通过某种方式实现 ISerializable 来解决,但我们必须保持与现有应用程序的兼容性,所以我不能更改它的序列化内容(使用新版本序列化的对象也必须使用旧版本打开) .
    • @Adriano 如果你实现了ISerializable,你也可以控制序列化,所以你可以用旧版本可以反序列化的方式序列化对象。
    • @svick 我不明白这一点! :) 如果我实现 ISerializable,我可能会序列化 MemberInfoSerializationHolder 的“我自己的版本”(假设是 MyMemberInfoSerializationHolder,我想只是 .NET 4 的旧实现)但是旧版本(不实现 ISerializable)将无法反序列化它。
    • @Adriano 但是你可以选择你如何实现ISerializable,所以你可以完全按照.Net 4.0 的方式来实现。如果你设法做到这一点,这两个版本将是兼容的。
    • @svick 我还是不明白。我以与序列化相同的方式序列化该类,并且对于该字段,我序列化“新”序列化持有者(模仿旧的)。它适用于新版本,但旧版本会尝试反序列化 MyMethodInfoSerializationHolder 并且它不会存在......或不存在?
    【解决方案2】:

    最后我自己无法完全解决这个问题。我尝试使用MemberInfoSerializationHoldercustom 实现来实现ISerializable,以模仿旧行为(只是粘贴了4.0 版本的代码)。它适用于 new 存档,但不适用于此场景的旧(已部署)应用程序。 我没有找到解决此问题的任何方法,因为已经发布的应用程序将无法运行(除非应用了补丁,但这是不可行的)。

    我看到在较新的版本中实现稍微改变了一点,只有当有多个具有相同名称的方法(然后使用签名)时才会预设问题,否则只会选择第一个(也是唯一的)一个,而无需任何额外检查。

    【讨论】:

      猜你喜欢
      • 2020-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-09
      • 1970-01-01
      相关资源
      最近更新 更多