从多个源和不同模式序列化对象的更顺畅方法?
Posted
技术标签:
【中文标题】从多个源和不同模式序列化对象的更顺畅方法?【英文标题】:Smoother way to Serialize the Objects from muliple Source and different Schema? 【发布时间】:2016-08-25 14:04:47 【问题描述】:我正在尝试为我的对象组成一个序列化,它可以来自多个源,比如源 1 和源 2,模式处理在两者中都非常糟糕。所以我试图处理一个平滑的序列化。
void CSerFoo::Serialize(CArchive& ar)
try
//ar.Flush();
SerializeEx(ar); // For the Serialization of the Good Ones, from the point now on
catch(...) // If the Object cannot be Serialized using the above Method try the Next way to decode
try
//ar.Flush();
SpecialSerialize1(ar); // For the Serialization of the Objects from the Source 1, actually code from the Source 1
catch(...) // If the Object cannot be Serialized using the above Method try the Last way to decode
try
//ar.Flush();
SpecialSerialize2(ar); // For the Serialization of the Objects from the Source 2, actually code from the Source 2
catch(...)
// No way
编辑 1:
这是来自源代码 1 的序列化代码
// From Source 1
IMPLEMENT_SERIAL( CSerFoo, CObject, VERSIONABLE_SCHEMA | 3)
void CSerFoo::Serialize(CArchive& ar) // This will be the Consolidated CSerFoo's SpecialSerialize1
UINT uiSchema = ar.GetObjectSchema();
if (ar.IsStoring())
ar << m_sName;
ar << m_sDesc;
ar << m_String1;
ar << m_fValue1;
ar << m_fValue2;
ar << m_iValue1;
ar << m_iValue2;
ar << m_String2;
ar << m_String3;
else
ar >> m_sName;
ar >> m_sDesc;
ar >> m_String1;
if(uischema > 0)// Added in VERSION_SCHEMA 1
ar >> m_fValue1;
ar >> m_fValue2;
if(uischema > 1) // Added in VERSION_SCHEMA 2
ar >> m_iValue1;
ar >> m_iValue2;
ar >> m_String4;
if(uischema > 2) // Added in VERSION_SCHEMA 3
ar >> m_String2;
ar >> m_String3;
这是来自源代码 2 的序列化代码
// From Source 2
IMPLEMENT_SERIAL( CSerFoo, CObject, VERSIONABLE_SCHEMA | 3)
void CSerFoo::Serialize(CArchive& ar) // This will be the Consolidated CSerFoo's SpecialSerialize2
UINT uiSchema = ar.GetObjectSchema();
if (ar.IsStoring())
ar << m_sName;
ar << m_sDesc;
ar << m_String1;
ar << m_fValue1;
ar << m_fValue2;
ar << m_iValue1;
ar << m_iValue2;
ar << m_iValue3;
ar << m_String2;
ar << m_String3;
else
ar >> m_sName;
ar >> m_sDesc;
ar >> m_String1;
if(uischema > 0)// Added in VERSION_SCHEMA 1
ar >> m_fValue1;
if(uischema > 1) // Added in VERSION_SCHEMA 2
ar >> m_fValue2;
ar >> m_iValue1;
ar >> m_iValue2;
if(uischema > 2) // Added in VERSION_SCHEMA 3
ar >> m_iValue3;
ar >> m_String2;
ar >> m_String3;
// m_String4 is not there in the Source 2
现在合并的CSerFoo
(从现在开始)具有来自两个源的所有字段,我们希望对同一 CSerFoo 对象进行更新的序列化。我们不能在创建另一个类上妥协。
我面临的问题是,在随后的序列化调用中,光标(CArchive::m_lpBufCur)被移动,因此下一次序列化尝试失败。
有没有办法做到这一点?
我错过了什么吗?
提前致谢!
【问题讨论】:
在不知道 SerializeEx 和 SpecialSerializeX 做什么的情况下,这很难说。 这只是对 int、float 和 string 的序列化。每个序列化的序列和字段数可能不同,这就是问题所在。 没有问题,当使用可版本化模式时,可版本化模式是您发明的问题的标准解决方案。简介见CArchive::GetObjectSchema,详情见TN002: Persistent Object Data Format。无论如何,所提出的问题是无法回答的。请提供minimal reproducible example,以便我们有一个共同的基础。 没有干净的方法可以解决您自己编写的混乱局面。 (我什至不知道您是如何说服链接器接受具有相同名称的两个对象CSerFoo
。)您必须重写整个序列化基础架构才能重新开始工作。即便如此,解决您违反单一定义规则的问题也是相当复杂的。由于 MFC 将类名存储到序列化流中,因此 SDR 也适用于 MFC 的序列化流。您应该聘请开发人员...
我不建议这样做,但每个 CArchive
(CArchive::GetFile()) 中都有一个 CFile。 CFile
有 GetPosition() 和 Seek() 成员。您还需要修复异常处理。 MFC 异常不会自动清除(请参阅Exception Handling in MFC)。
【参考方案1】:
如果您没有strong exepction safety guarantee,异常似乎是解决此问题的错误方法。
因此您可以实现函数,使其遵守它(仅在函数中使用局部偏移,而不是像 CArchive 对象内部的偏移或在函数内部复制它)
但似乎异常在这里被滥用为控制结构。您也许应该考虑仅在“异常”情况下使用异常,并具有一些功能,例如
if(isFormat1Convertible(ar))
SerializeEx(ar);
else if(isFormat2Convertible(ar))
SpecialSerialize1(ar);
...
在我看来,这更像是更简洁的代码,并且不会“滥用”异常。
【讨论】:
一个不明白的人写的粗鲁的东西Serialization in MFC。至于异常,应该在函数未能兑现承诺时抛出。这是否致命(或“异常”)由客户端代码决定。一般来说,抛出异常的代码几乎不知道这种失败在上下文中是否是致命的。 是的,这不是“MFC”方式,但我更喜欢“进入”一种语言/框架而不是“进入”一种语言(请参阅“代码完成”第 4 章了解关于这)。并且在互联网/书籍上进行了一些讨论,将 OP 中异常的这种用法视为“代码气味”(并且 OP 存在一些问题,否则该帖子将不存在)。我有一段时间没有使用 MFC,但正如我从文档中看到的那样,有一个叫做“VERSIONABLE_SCHEMA”的东西。也许这可以用来选择正确的格式而不是异常(或其他方法,但这取决于具体情况)。 您必须了解一个框架才能做出明智的决定,无论您是想在其中编程还是在其中编程。 Code Complete 的建议带有理由。您缺乏洞察力使您无法应用它。再说了,你不能编程进MFC的序列化,除非你改了,打破了规则,然后来这里寻求帮助解决你搞砸的烂摊子。 是的,你就在那儿。这主要是对不同设计的建议。要创建“强异常安全”,只需重新打开文件并为每个调用创建一个新的 CArchive 对象就足够了(这在我的回答的第一部分中有所暗示)。或者,如果它来自另一个缓冲区,请在将其加载到 CArchive 之前复制该缓冲区。虽然效率不高。以上是关于从多个源和不同模式序列化对象的更顺畅方法?的主要内容,如果未能解决你的问题,请参考以下文章