将代码移入命名空间后的序列化异常

时间:2015-10-22 09:03:37

标签: .net visual-c++ serialization c++-cli binaryformatter

我将c ++ / cli(visual studio 2010)项目的代码移动到命名空间中。在此之前,一切都在全局命名空间中,但这有几个缺点需要解决。

重命名后,现有保存文件的二进制反序列化失败,并显示以下错误消息:

Serialization Exception occurred.
The object with ID 11 was referenced in a fixup but does not exist.

为了解决这些类的重命名问题 - 现在它们位于命名空间中 - 我使用了SerializationBinder。

ref class MySerializationBinder sealed: SerializationBinder
{
public:
    virtual Type^ BindToType (String^ assemblyname, String^ typeName) override
    {
        Type^ result = Type::GetType (typeName);
        if (result == nullptr)
        {
            result = Type::GetType ("MyNamespace." + typeName);
        }
        return result;
    }
};

有没有人知道这里可能出现的问题?

1 个答案:

答案 0 :(得分:1)

将代码从How to create a SerializationBinder for the Binary Formatter that handles the moving of types from one assembly and namespace to another翻译成非常快的n脏c ++ cli,我们得到类似

的内容
virtual Type^ BindToType (String^ assemblyName, String^ typeName) override
{
    auto m = Regex::Match (typeName, "^(?<gen>[^\\[]+)\\[\\[(?<type>[^\\]]*)\\](,\\[(?<type>[^\\]]*)\\])*\\]$");
    if (m->Success)
    {
        // generic type
        Type^ gen = GetFlatTypeMapping (assemblyName, m->Groups["gen"]->Value);
        List<Type^>^ genArgs = gcnew List<Type^> ();
        for each(Capture^ c in Enumerable::Cast<Capture^> (m->Groups["type"]->Captures)){
            Match^ m2 = Regex::Match (c->Value, "^(?<tname>.*)(?<aname>(,[^,]+){4})$");
            String^ tname = m2->Groups["tname"]->Value->Trim ();
            Type^ t = BindToType ("", tname);
            genArgs->Add(t);
        }
        return gen->MakeGenericType (genArgs->ToArray ());
    }
    return GetFlatTypeMapping (assemblyName, typeName);
}

Type^ GetFlatTypeMapping (String^ assemblyName, String^ typeName)
{
    Type^ result = Type::GetType (typeName);
    if (result == nullptr)
    {
        result = Type::GetType ("MyNamespace." + typeName);
    }
    if (result == nullptr)
    {
        if (typeName->Contains ("BindingList"))
            result = BindingList<int>::typeid->GetGenericTypeDefinition (); //int is just a placeholder
        if (typeName->Contains ("KeyValuePair"))
            result = KeyValuePair<int, int>::typeid->GetGenericTypeDefinition (); //int is just a placeholder
    }
    if (result == nullptr)
        throw gcnew Exception ("Fail");
    return result;
}

但是,由于我知道要翻译哪些类,因此我发现以下方法更容易。这样我们也不必关心嵌套泛型。变量OldClassList被假定为包含必须移入命名空间MyNamespace的类名的字符串列表。

virtual Type^ BindToType (String^ assemblyName, String^ typeName) override
{
    String^ newTypeName = typeName;
    for each(String^ name in OldClassList)
        newTypeName = Regex::Replace (newTypeName, "(?<![.\\w])" + name + "\\b", "MyNamespace." + name);
    newTypeName = Regex::Replace (newTypeName, "\\OldAssembly, Version", "NewAssembly, Version");

    Type^ result = Type::GetType (newTypeName);
    if (result == nullptr)
        throw gcnew Exception ("Could not parse the string {0} to a valid type."->Format(typeName));

    return result;
}