永続化と初期化の最適化
既定では、コントロールの永続化と初期化は DoPropExchange
メンバー関数で処理されます。 一般的なコントロールでは、この関数には、各プロパティごとに複数の PX_ 関数 (PX_Color
、PX_Font
など) の呼び出しを含んでいます。
このアプローチには、1つ DoPropExchange
の実装を初期化に使用したり、バイナリ形式で永続化したり、一部のコンテナーで使用されるいわゆる "プロパティ バッグ" 形式で永続化するという利点があります。 この 1 つの関数は、プロパティとその既定値に関するすべての情報を 1 つの便利な場所に提供します。
ただし、この一般性には効率の低下が伴います。 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 の 1 バイトだけが変更され、残りのバイトは初期化されません。
同じコントロールに対して、次のように 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();
}
Serialize
と OnResetState
はオーバーライドされましたが、DoPropExchange
関数は、プロパティバッグ形式で永続化に使用されているため、そのまま保持される必要があります。 これら 3 つの関数をすべて維持して、コンテナーが使用する永続化メカニズムに関係なく、コントロールのプロパティが一貫して管理されるようにすることが重要です。