PowerTools SPREAD for Windows Forms 10.0J
Serializer クラスの実装

Serializerクラスを使用する場合、以下の点に注意してください。

データ型とシリアル化

後述のサンプルコードでは、整数値や色など単純なデータを保存する方法を示していますが、他のタイプのデータを保存する場合も、同様です。Serializerクラスには、Color、DateTime、DateTimeFormatInfo、Enum型、Font、Image、Int32配列、NumberFormatInfo、PointF配列、String配列、およびObjectを、それぞれ保存および読み込むためのメソッドが存在します。可能な限り限定的なメソッドを使用することをお勧めします。たとえば、単純型やColor値の保存にSerializeObjectメソッドを使用することもできますが、効率的ではなく、同一のXMLを復元できない場合もあります。

特定の型に対して作成されたメソッドには、概して理由があります。DateTimeFormatInfoおよびNumberFormatInfoオブジェクトは、それぞれ固有のメソッドを使用して保存する必要があります。SerializeObjectメソッドでは、既定でバイナリ型のシリアル化が使用されますが、この方法では、フレームワークのバージョンが異なると正しく機能しません。たとえば、.NET 1.0を使用して保存されたDateTimeFormatInfoは、.NET 1.1または2.0を使用して読み込むことができません。

Int32、String、Boolean などの単純型の場合は、単純に ToString() を使用して文字列に変換してから保存し(可能な場合、CultureInfoクラスのInvariantCultureプロパティの値を指定して)、XmlConvertクラスを使用して文字列を値に戻す方法が最適です。

SaveObjectメソッドは、ISerializeSupportインタフェースを実装するオブジェクト、特定の型(組み込みのデータ型およびDataSetオブジェクト)、およびシリアル化が可能ではあるもののISerializeSupportインタフェースを実装していないオブジェクトの保存を目的としています。このようなオブジェクトは、EncodeObjectメソッドを使用して保存されます。EncodeObjectメソッドは、BinaryFormatterクラスを使用してオブジェクトをMemoryStreamオブジェクトに保存してから、Convertクラスを使用してBase64文字列にエンコードします。

デバッグおよびリリースビルド

デバッグビルドによってファイルを保存し、厳密な名前の付いたリリースビルドとしてロードするには、オブジェクトを保存したノードでアセンブリ属性を除去または更新する必要があります。SerializeObjectメソッドは、オブジェクトの型を定義したアセンブリが、呼び出しアセンブリおよび実行アセンブリ(FarPoint.Win.dll)と異なる場合、アセンブリ属性を記述します。

呼び出しアセンブリは、通常、FarPoint.Win.Spread.dllです。しかし、開発者がISerializeSupportインタフェースを実装する独自のオブジェクトを定義し、SerializeObjectメソッドを使用して子オブジェクトを保存している場合、開発者のアセンブリとなる場合があります。注意が必要な例として、開発者が、製品のオブジェクトモデルに組み込むカスタムオブジェクト(たとえば、独自のデータモデル)を作成した場合に、コントロールの保存と読み込みにはFpSpreadクラスの保存および読み込みメソッドを使用し、作成したアセンブリの異なるビルドを使用しようとする状況が考えられます。

この場合、オブジェクトの型定義を含む適切なアセンブリを読み込むために、アセンブリ属性が必要ですが、デバッグビルドとリリースビルドでは正しい属性が異なります。このような場合、XML内の値を編集して、アセンブリ参照を変更する必要があります(StringクラスのReplaceメソッドなどを使用)。

稀なケースでは、ISerializeSupportインタフェース、およびSerializerクラスを使用して、独自に定義したオブジェクトを含むファイルを保存および読み込む場合にも注意が必要です。このようなオブジェクトは、同一アセンブリ内に含まれることも、並行して記述している別のアセンブリに含まれることもあります。各オブジェクトが同一アセンブリ内で定義されている場合、アセンブリ属性は出力されません。異なるアセンブリで定義されている場合、callingAssembly引数を受け取るSerializeObject、およびCreateObjectInstanceAndDeserializeメソッドのオーバーロードを呼び出して、該当オブジェクトを保持するアセンブリ(Serializerクラスを呼び出したアセンブリでなくてもかまわない)を渡すことができます。これにより、アセンブリ属性が出力されなくなります。重要な点は、この処理を保存、および読み込みの呼び出しの両方で行うことです。これにより、型参照が解決され、オブジェクトのインスタンスが作成されます。

サンプルコード1

次のサンプルコードは、LineBorderクラスを例に、製品でISerializeSupportインタフェースがどのように実装されているかを示します。

C#
コードのコピー
// ISerializeSupportインタフェースの実装には、引数なしのコンストラクタが必要です。
// パブリックである必要はありません。
internal LineBorder()
{
    color = SystemColors.WindowFrame;
    thickness = 1;
    left = top = right = bottom = true;
    inset = new FarPoint.Win.Inset(1);      
}
/// <summary>
/// オブジェクトを XML に保存します。
/// </summary>
/// <param name="w">オブジェクトの保存先となる XmlTextWriter オブジェクトです。</param>
/// <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
public virtual bool Serialize(System.Xml.XmlTextWriter w)
{
    w.WriteStartElement("Inset");
    w.WriteElementString("Bottom", inset.Bottom.ToString());
    w.WriteElementString("Left", inset.Left.ToString());
    w.WriteElementString("Right", inset.Right.ToString());
    w.WriteElementString("Top", inset.Top.ToString());
    w.WriteEndElement();
    FarPoint.Win.Serializer.SerializeColor(color, "Color", w);
    w.WriteStartElement("Sides");
    w.WriteElementString("Bottom", bottom.ToString());
    w.WriteElementString("Left", left.ToString());
    w.WriteElementString("Right", right.ToString());
    w.WriteElementString("Top", top.ToString());
    w.WriteEndElement();
    w.WriteElementString("Thickness", thickness.ToString(System.Globalization.CultureInfo.InvariantCulture));
    return true;
}
/// <summary>
/// XML からオブジェクトをロードします。
/// </summary>
/// <param name="r">オブジェクトをロードする XmlNodeReader です。</param>
/// <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
public virtual bool Deserialize(System.Xml.XmlNodeReader r)
{
    bool inInset = false;
    bool inBottom = false;
    bool inLeft = false;
    bool inRight = false;
    bool inTop = false;
    bool inColor = false;
    bool inSides = false;
    bool inThickness = false;
    int bottom = inset.Bottom;
    int left = inset.Left;
    int right = inset.Right;
    if (r.IsEmptyElement)
        return true;
    while (r.Read())
    {
        switch (r.NodeType)
        {
            case System.Xml.XmlNodeType.Element:
                if (r.Name.Equals("Inset"))
                    inInset = true;
                else if (r.Name.Equals("Color"))
                    inColor = true;
                else if (r.Name.Equals("Sides"))
                    inSides = true;
                else if (inInset || inSides)
                {
                    if (r.Name.Equals("Bottom"))
                        inBottom = true;
                    else if (r.Name.Equals("Left"))
                        inLeft = true;
                    else if (r.Name.Equals("Right"))
                        inRight = true;
                    else if (r.Name.Equals("Top"))
                        inTop = true;
                }
                else if (r.Name.Equals("Thickness"))
                    inThickness = true;
                break;
            case System.Xml.XmlNodeType.Text:
                if (inInset)
                {
                    if (inBottom)
                        bottom = System.Xml.XmlConvert.ToInt32(r.Value);
                    else if (inLeft)
                        left = System.Xml.XmlConvert.ToInt32(r.Value);
                    else if (inRight)
                        right = System.Xml.XmlConvert.ToInt32(r.Value);
                    else if (inTop)
                        inset = new FarPoint.Win.Inset(left, System.Xml.XmlConvert.ToInt32(r.Value), right, bottom);
                }
                else if (inSides)
                {
                    if (inBottom)
                        this.bottom = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture));
                    else if (inLeft)
                        this.left = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture));
                    else if (inRight)
                        this.right = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture));
                    else if (inTop)
                        this.top = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture));
                }
                else if (inColor)
                    color = FarPoint.Win.Serializer.DeserializeColorValue(r.Value);
                else if (inThickness)
                    thickness = System.Xml.XmlConvert.ToInt32(r.Value);
                break;
            case System.Xml.XmlNodeType.EndElement:
                if (inInset && r.Name.Equals("Inset"))
                    inInset = false;
                else if (inColor && r.Name.Equals("Color"))
                    inColor = false;
                else if (inSides && r.Name.Equals("Sides"))
                    inSides = false;
                else if (inInset || inSides)
                {
                    if (inBottom && r.Name.Equals("Bottom"))
                        inBottom = false;
                    else if (inLeft && r.Name.Equals("Left"))
                        inLeft = false;
                    else if (inRight && r.Name.Equals("Right"))
                        inRight = false;
                    else if (inTop && r.Name.Equals("Top"))
                        inTop = false;
                }
                else if (inThickness && r.Name.Equals("Thickness"))
                    // サブクラスを逆シリアル化するため、ここで処理を終了します。
                    return true;
                break;
        }
    }
    return true;
}
Visual Basic
コードのコピー
' ISerializeSupportインタフェースの実装には、引数なしのコンストラクタが必要です。
' パブリックである必要はありません。
Friend Sub New()
    color = SystemColors.WindowFrame
    thickness = 1
    left = True
    top = True
    right = True
    bottom = True
    inset = New FarPoint.Win.Inset(1)
End Sub
''' <summary>
''' オブジェクトを XML に保存します。
''' </summary>
''' <param name="w">オブジェクトの保存先となる XmlTextWriter オブジェクトです。</param>
''' <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
Public Overridable Function Serialize(w As System.Xml.XmlTextWriter) As Boolean
    w.WriteStartElement("Inset")
    w.WriteElementString("Bottom", inset.Bottom.ToString())
    w.WriteElementString("Left", inset.Left.ToString())
    w.WriteElementString("Right", inset.Right.ToString())
    w.WriteElementString("Top", inset.Top.ToString())
    w.WriteEndElement()
    FarPoint.Win.Serializer.SerializeColor(color, "Color", w)
    w.WriteStartElement("Sides")
    w.WriteElementString("Bottom", bottom.ToString())
    w.WriteElementString("Left", left.ToString())
    w.WriteElementString("Right", right.ToString())
    w.WriteElementString("Top", top.ToString())
    w.WriteEndElement()
    w.WriteElementString("Thickness", thickness.ToString(System.Globalization.CultureInfo.InvariantCulture))
    Return True
End Function
''' <summary>
''' XML からオブジェクトをロードします。
''' </summary>
''' <param name="r">オブジェクトをロードする XmlNodeReader です。</param>
''' <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
Public Overridable Function Deserialize(r As System.Xml.XmlNodeReader) As Boolean
    Dim inInset As Boolean = False
    Dim inBottom As Boolean = False
    Dim inLeft As Boolean = False
    Dim inRight As Boolean = False
    Dim inTop As Boolean = False
    Dim inColor As Boolean = False
    Dim inSides As Boolean = False
    Dim inThickness As Boolean = False
    Dim bottom As Integer = inset.Bottom
    Dim left As Integer = inset.Left
    Dim right As Integer = inset.Right
    If r.IsEmptyElement Then
        Return True
    End If
    While r.Read()
        Select Case r.NodeType
            Case System.Xml.XmlNodeType.Element
                If r.Name.Equals("Inset") Then
                    inInset = True
                ElseIf r.Name.Equals("Color") Then
                    inColor = True
                ElseIf r.Name.Equals("Sides") Then
                    inSides = True
                ElseIf inInset OrElse inSides Then
                    If r.Name.Equals("Bottom") Then
                        inBottom = True
                    ElseIf r.Name.Equals("Left") Then
                        inLeft = True
                    ElseIf r.Name.Equals("Right") Then
                        inRight = True
                    ElseIf r.Name.Equals("Top") Then
                        inTop = True
                    End If
                ElseIf r.Name.Equals("Thickness") Then
                    inThickness = True
                End If
                Exit Select
            Case System.Xml.XmlNodeType.Text
                If inInset Then
                    If inBottom Then
                        bottom = System.Xml.XmlConvert.ToInt32(r.Value)
                    ElseIf inLeft Then
                        left = System.Xml.XmlConvert.ToInt32(r.Value)
                    ElseIf inRight Then
                        right = System.Xml.XmlConvert.ToInt32(r.Value)
                    ElseIf inTop Then
                        inset = New FarPoint.Win.Inset(left, System.Xml.XmlConvert.ToInt32(r.Value), right, bottom)
                    End If
                ElseIf inSides Then
                    If inBottom Then
                        Me.bottom = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture))
                    ElseIf inLeft Then
                        Me.left = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture))
                    ElseIf inRight Then
                        Me.right = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture))
                    ElseIf inTop Then
                        Me.top = System.Xml.XmlConvert.ToBoolean(r.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture))
                    End If
                ElseIf inColor Then
                    color = FarPoint.Win.Serializer.DeserializeColorValue(r.Value)
                ElseIf inThickness Then
                    thickness = System.Xml.XmlConvert.ToInt32(r.Value)
                End If
                Exit Select
            Case System.Xml.XmlNodeType.EndElement
                If inInset AndAlso r.Name.Equals("Inset") Then
                    inInset = False
                ElseIf inColor AndAlso r.Name.Equals("Color") Then
                    inColor = False
                ElseIf inSides AndAlso r.Name.Equals("Sides") Then
                    inSides = False
                ElseIf inInset OrElse inSides Then
                    If inBottom AndAlso r.Name.Equals("Bottom") Then
                        inBottom = False
                    ElseIf inLeft AndAlso r.Name.Equals("Left") Then
                        inLeft = False
                    ElseIf inRight AndAlso r.Name.Equals("Right") Then
                        inRight = False
                    ElseIf inTop AndAlso r.Name.Equals("Top") Then
                        inTop = False
                    End If
                ElseIf inThickness AndAlso r.Name.Equals("Thickness") Then
                    ' サブクラスを逆シリアル化するため、ここで処理を終了します。
                    Return True
                End If
                Exit Select
        End Select
    End While
    Return True
End Function
サンプルコード2

次のサンプルコードは、派生クラスでの処理の実装例を示します。

C#
コードのコピー
// ISerializeSupport には、引数なしのコンストラクタが必要です。
// パブリックである必要はありません。
protected GradientLineBorder():base(SystemColors.WindowFrame, 1, true, true, true, true)
{
    startColor = Color.Blue;
    endColor = Color.Green;
}       
/// <summary>
/// オブジェクトを XML に保存します。
/// </summary>
/// <param name="w">オブジェクトの保存先となる XmlTextWriter オブジェクトです。</param>
/// <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
public override bool Serialize(System.Xml.XmlTextWriter w)
{
    if (!base.Serialize(w))
        return false;
    FarPoint.Win.Serializer.SerializeColor(startColor, "StartColor", w);
    FarPoint.Win.Serializer.SerializeColor(endColor, "EndColor", w);
    return true;
}
/// <summary>
/// XML からオブジェクトをロードします。
/// </summary>
/// <param name="r">オブジェクトをロードする XmlNodeReader です。</param>
/// <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
public override bool Deserialize(System.Xml.XmlNodeReader r)
{
    bool inStartColor = false;
    bool inEndColor = false;
    if (r.IsEmptyElement)
        return true;
    if (!base.Deserialize(r))
        return false;
    while (r.Read())
    {
        switch (r.NodeType)
        {
            case System.Xml.XmlNodeType.Element:
                if (r.Name.Equals("StartColor"))
                    inStartColor = true;
                else if (r.Name.Equals("EndColor"))
                    inEndColor = true;
                break;
            case System.Xml.XmlNodeType.Text:
                if (inStartColor)
                    startColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value);
                else if (inEndColor)
                    endColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value);
                break;
            case System.Xml.XmlNodeType.EndElement:
                if (inStartColor && r.Name.Equals("StartColor"))
                    inStartColor = false;
                else if (inEndColor && r.Name.Equals("EndColor"))
                    // サブクラスを逆シリアル化するため、ここで処理を終了します。
                    return true;
                break;
        }
    }
    return true;
}
Visual Basic
コードのコピー
' ISerializeSupport には、引数なしのコンストラクタが必要です。
' パブリックである必要はありません。
Protected Sub New()
    MyBase.New(SystemColors.WindowFrame, 1, True, True, True, True)
    startColor = Color.Blue
    endColor = Color.Green
End Sub
''' <summary>
''' オブジェクトを XML に保存します。
''' </summary>
''' <param name="w">オブジェクトの保存先となる XmlTextWriter オブジェクトです。</param>
''' <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
Public Overrides Function Serialize(w As System.Xml.XmlTextWriter) As Boolean
    If Not MyBase.Serialize(w) Then
        Return False
    End If
    FarPoint.Win.Serializer.SerializeColor(startColor, "StartColor", w)
    FarPoint.Win.Serializer.SerializeColor(endColor, "EndColor", w)
    Return True
End Function
''' <summary>
''' XML からオブジェクトをロードします。
''' </summary>
''' <param name="r">オブジェクトをロードする XmlNodeReader です。</param>
''' <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
Public Overrides Function Deserialize(r As System.Xml.XmlNodeReader) As Boolean
    Dim inStartColor As Boolean = False
    Dim inEndColor As Boolean = False
    If r.IsEmptyElement Then
        Return True
    End If
    If Not MyBase.Deserialize(r) Then
        Return False
    End If
    While r.Read()
        Select Case r.NodeType
            Case System.Xml.XmlNodeType.Element
                If r.Name.Equals("StartColor") Then
                    inStartColor = True
                ElseIf r.Name.Equals("EndColor") Then
                    inEndColor = True
                End If
                Exit Select
            Case System.Xml.XmlNodeType.Text
                If inStartColor Then
                    startColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value)
                ElseIf inEndColor Then
                    endColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value)
                End If
                Exit Select
            Case System.Xml.XmlNodeType.EndElement
                If inStartColor AndAlso r.Name.Equals("StartColor") Then
                    inStartColor = False
                ElseIf inEndColor AndAlso r.Name.Equals("EndColor") Then
                    ' サブクラスを逆シリアル化するため、ここで処理を終了します。
                    Return True
                End If
                Exit Select
        End Select
    End While
    Return True
End Function
サンプルコード3

次のサンプルコードは、XMLの属性にColorを保存する例です。先の例の、XMLの要素にColorを保存する方法に比べ、コード量が少なく、簡易的な方法です。

C#
コードのコピー
/// <summary>
/// オブジェクトを XML に保存します。
/// </summary>
/// <param name="w">オブジェクトの保存先となる XmlTextWriter オブジェクトです。</param>
/// <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
public override bool Serialize(System.Xml.XmlTextWriter w)
{
    w.WriteAttributeString("startColor", FarPoint.Win.Serializer.SerializeColorValue(startColor));
    w.WriteAttributeString("endColor", FarPoint.Win.Serializer.SerializeColorValue(endColor));
    return base.Serialize(w);
}
/// <summary>
/// XML からオブジェクトをロードします。
/// </summary>
/// <param name="r">オブジェクトをロードする XmlNodeReader です。</param>
/// <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
public override bool Deserialize(System.Xml.XmlNodeReader r)
{
    if (r.MoveToAttribute("startColor"))
        startColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value);
    if (r.MoveToAttribute("endColor"))
        endColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value);
    return base.Deserialize(r);
}
Visual Basic
コードのコピー
''' <summary>
''' オブジェクトを XML に保存します。
''' </summary>
''' <param name="w">オブジェクトの保存先となる XmlTextWriter オブジェクトです。</param>
''' <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
Public Overrides Function Serialize(w As System.Xml.XmlTextWriter) As Boolean
    w.WriteAttributeString("startColor", FarPoint.Win.Serializer.SerializeColorValue(startColor))
    w.WriteAttributeString("endColor", FarPoint.Win.Serializer.SerializeColorValue(endColor))
    Return MyBase.Serialize(w)
End Function
''' <summary>
''' XML からオブジェクトをロードします。
''' </summary>
''' <param name="r">オブジェクトをロードする XmlNodeReader です。</param>
''' <returns>成功した場合は True を、そうでない場合は False を返します。</returns>
Public Overrides Function Deserialize(r As System.Xml.XmlNodeReader) As Boolean
    If r.MoveToAttribute("startColor") Then
        startColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value)
    End If
    If r.MoveToAttribute("endColor") Then
        endColor = FarPoint.Win.Serializer.DeserializeColorValue(r.Value)
    End If
    Return MyBase.Deserialize(r)
End Function
関連トピック

 

 


© 2004-2017, GrapeCity inc. All rights reserved.