优化持久性和初始化

默认情况下,控件中的持久性和初始化由 DoPropExchange 成员函数处理。 在典型控件中,此函数包含对多个 PX_ 函数(PX_ColorPX_Font 等)的调用,针对每个属性调用一个。

这种方法的优点是,单个 DoPropExchange 实现可用于初始化、二进制格式的持久性,以及某些容器使用的所谓“属性包”格式的持久性。 这样一个函数在一个便捷位置提供了有关属性及其默认值的所有信息。

不过,这种普遍性以牺牲效率为代价。 PX_ 函数通过多层实现获得灵活性,与更直接但灵活性更低的方法相比,这些实现在本质上效率更低。 此外,如果控件将默认值传递给 PX_ 函数,则每次都必须提供默认值,即使在可能不一定会使用默认值的情况下也是如此。 如果生成默认值很重要(例如,在从环境属性中获取值时),那么在不使用默认值的情况下,就需要做不必要的额外工作。

可通过替代控件的 Serialize 函数来提高控件的二进制持久性性能。 此成员函数的默认实现对函数 DoPropExchange 进行调用。 通过替代它,可以为二进制持久性提供更直接的实现。 例如,请考虑使用 DoPropExchange 函数:

void CMyAxOptCtrl::DoPropExchange(CPropExchange* pPX)
{
   ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
   COleControl::DoPropExchange(pPX);

   PX_Bool(pPX, _T("BoolProp"), m_BoolProp, TRUE);
   PX_Short(pPX, _T("ShortProp"), m_ShortProp, 0);
   PX_Color(pPX, _T("ColorProp"), m_ColorProp, RGB(0xFF, 0x00, 0x00));
   PX_String(pPX, _T("StringProp"), m_StringProp, _T(""));
}

若要提高此控件的二进制持久性的性能,可按如下所示替代 Serialize 函数:

void CMyAxOptCtrl::Serialize(CArchive& ar)
{
   SerializeVersion(ar, MAKELONG(_wVerMinor, _wVerMajor));
   SerializeExtent(ar);
   SerializeStockProps(ar);

   if (ar.IsLoading())
   {
      ar >> m_BoolProp;
      ar >> m_ShortProp;
      ar >> m_ColorProp;
      ar >> m_StringProp;
   }
   else
   {
      ar << m_BoolProp;
      ar << m_ShortProp;
      ar << m_ColorProp;
      ar << m_StringProp;
   }
}

dwVersion 局部变量可用于检测正在加载或保存的控件持久状态的版本。 可以使用此变量,而不是调用 CPropExchange::GetVersion

若要在 BOOL 属性的持久格式中节省一点空间(并保持它与 PX_Bool 生成的格式的兼容性),你可以 BYTE 形式保存属性,如下所示:

if (ar.IsLoading())
{
   BYTE bTmp;
   ar >> bTmp;
   m_BoolProp = (BOOL)bTmp;
   // other properties...
}
else
{
   ar << (BYTE)m_BoolProp;
   // other properties...
}

请注意,在加载情况下,将使用临时变量,然后分配其值,而不是将 m_boolProp 强制转换为 BYTE 引用。 强制转换技术会导致仅修改 m_boolProp 的一个字节,并将剩余的字节保持在未初始化状态。

对于同一控件,可通过替代 COleControl::OnResetState 来优化控件的初始化,如下所示:

void CMyAxOptCtrl::OnResetState()
{
   ResetVersion(MAKELONG(_wVerMinor, _wVerMajor));
   ResetStockProps();

   m_BoolProp = TRUE;
   m_ShortProp = 0;
   m_ColorProp = RGB(0xFF, 0x00, 0x00);
   m_StringProp.Empty();
}

虽然已替代 SerializeOnResetState,但 DoPropExchange 函数应保持完整,因为它仍用于属性包格式的持久性。 请务必维护这三个函数,确保控件一致地管理其属性,而不管容器使用哪种持久性机制。

另请参阅

MFC ActiveX 控件:优化