注意:ここではDataContractSerializerクラスを使った方法を紹介します。XmlSerializerクラスを使った方法は、「Object配列やArrayListをXMLシリアル化する」で説明しています。
「DataContractSerializerを使って、オブジェクトのXMLシリアル化、逆シリアル化を行う」の方法では、Object型の配列や、ArrayListオブジェクト、あるいはObject型のプロパティを持つオブジェクトなどをシリアル化する時、例外System.Runtime.Serialization.SerializationExceptioがスローされる場合があります。例えば以下のようなケースです。
Imports System.Runtime.Serialization Imports System.Xml Imports System.Collections <DataContract> _ Public Class SampleItem <DataMember> _ Public Number As Integer <DataMember> _ Public Message As String Public Sub New() Number = 0 Message = "" End Sub Public Sub New(num As Integer, msg As String) Number = num Message = msg End Sub End Class Public Class MainClass 'エントリポイント Public Shared Sub Main() '保存先のファイル名 Dim fileName As String = "C:\test\test.xml" 'シリアル化するArrayList Dim al As New ArrayList() al.Add(New SampleItem(12, "こんにちは")) 'シリアル化する Dim serializer As New DataContractSerializer(GetType(ArrayList)) Dim settings As New XmlWriterSettings() settings.Encoding = New System.Text.UTF8Encoding(False) Dim xw As XmlWriter = XmlWriter.Create(fileName, settings) 'SerializationExceptioがスローされる serializer.WriteObject(xw, al) xw.Close() End Sub End Class
using System.Runtime.Serialization; using System.Xml; using System.Collections; [DataContract] public class SampleItem { [DataMember] public int Number; [DataMember] public string Message; public SampleItem() { Number = 0; Message = ""; } public SampleItem(int num, string msg) { Number = num; Message = msg; } } public class MainClass { //エントリポイント public static void Main() { //保存先のファイル名 string fileName = @"C:\test\test.xml"; //シリアル化するArrayList ArrayList al = new ArrayList(); al.Add(new SampleItem(12, "こんにちは")); //シリアル化する DataContractSerializer serializer = new DataContractSerializer(typeof(ArrayList)); XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = new System.Text.UTF8Encoding(false); XmlWriter xw = XmlWriter.Create(fileName, settings); //SerializationExceptioがスローされる serializer.WriteObject(xw, al); xw.Close(); } }
ここでは、このような場合の対処法を紹介します。
まず、ArrayListに追加されているすべての型のコレクションをDataContractSerializerのコンストラクタに指定するという解決法があります。
この方法によって上記の例を書き換えると、次のようになります。書き換えたのは、Typeの配列を作成する部分と、DataContractSerializerのコンストラクタを呼び出す部分だけです。
Imports System.Runtime.Serialization Imports System.Xml Imports System.Collections <DataContract> _ Public Class SampleItem <DataMember> _ Public Number As Integer <DataMember> _ Public Message As String Public Sub New() Number = 0 Message = "" End Sub Public Sub New(num As Integer, msg As String) Number = num Message = msg End Sub End Class Public Class MainClass Public Shared Sub Main() Dim fileName As String = "C:\test\test.xml" Dim al As New ArrayList() al.Add(New SampleItem(12, "こんにちは")) 'ArrayListに追加されているオブジェクトの型の配列を作成 Dim knownTypes As Type() = New Type() {GetType(SampleItem)} '予想される型を指定して、DataContractSerializerを作成 Dim serializer As New DataContractSerializer( _ GetType(ArrayList), knownTypes) 'シリアル化できるようになる Dim settings As New XmlWriterSettings() settings.Encoding = New System.Text.UTF8Encoding(False) Dim xw As XmlWriter = XmlWriter.Create(fileName, settings) serializer.WriteObject(xw, al) xw.Close() End Sub End Class
using System; using System.Runtime.Serialization; using System.Xml; using System.Collections; [DataContract] public class SampleItem { [DataMember] public int Number; [DataMember] public string Message; public SampleItem() { Number = 0; Message = ""; } public SampleItem(int num, string msg) { Number = num; Message = msg; } } public class MainClass { public static void Main() { string fileName = @"C:\test\test.xml"; ArrayList al = new ArrayList(); al.Add(new SampleItem(12, "こんにちは")); //ArrayListに追加されているオブジェクトの型の配列を作成 Type[] knownTypes = new Type[] { typeof(SampleItem) }; //予想される型を指定して、DataContractSerializerを作成 DataContractSerializer serializer = new DataContractSerializer(typeof(ArrayList), knownTypes); //シリアル化できるようになる XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = new System.Text.UTF8Encoding(false); XmlWriter xw = XmlWriter.Create(fileName, settings); serializer.WriteObject(xw, al); xw.Close(); } }
上記のコードで作成されるXMLファイルの内容は、以下のようになります(見やすいように改行を入れています)。
<?xml version="1.0" encoding="utf-8"?> <ArrayOfanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <anyType xmlns:d2p1="http://schemas.datacontract.org/2004/07/" i:type="d2p1:SampleItem"> <d2p1:Message>こんにちは</d2p1:Message> <d2p1:Number>12</d2p1:Number></anyType> </ArrayOfanyType>
リシアル化したいオブジェクトのメンバがObjectやObject配列、コレクションである場合は、そのクラスにKnownTypeAttributeを適用して、認識すべき型を指定しておく方法もあります。このようなクラスを作れば、通常の方法でシリアル化できるようになります。
以下に例を示します。ここではSampleClassクラスにKnownTypeAttributeを適用し、SampleClassオブジェクトをシリアル化できるようにしています。
Imports System.Runtime.Serialization Imports System.Xml Imports System.Collections <DataContract> _ Public Class SampleItem <DataMember> _ Public Number As Integer <DataMember> _ Public Message As String Public Sub New() Number = 0 Message = "" End Sub Public Sub New(num As Integer, msg As String) Number = num Message = msg End Sub End Class 'KnownTypeAttributeを適用し、シリアル化の時に認識すべき型を指定する <DataContract> _ <KnownType(GetType(SampleItem))> _ Public Class SampleClass <DataMember> _ Public Items As System.Collections.ArrayList Public Sub New() Items = New System.Collections.ArrayList() Items.Add(New SampleItem(12, "こんにちは")) End Sub End Class Public Class MainClass Public Shared Sub Main() Dim fileName As String = "C:\test\test.xml" 'シリアル化するオブジェクト Dim obj As New SampleClass() '普通にシリアル化できるようになる Dim serializer As New DataContractSerializer(GetType(SampleClass)) Dim settings As New XmlWriterSettings() settings.Encoding = New System.Text.UTF8Encoding(False) Dim xw As XmlWriter = XmlWriter.Create(fileName, settings) serializer.WriteObject(xw, obj) xw.Close() End Sub End Class
using System.Runtime.Serialization; using System.Xml; using System.Collections; [DataContract] public class SampleItem { [DataMember] public int Number; [DataMember] public string Message; public SampleItem() { Number = 0; Message = ""; } public SampleItem(int num, string msg) { Number = num; Message = msg; } } //KnownTypeAttributeを適用し、シリアル化の時に認識すべき型を指定する [DataContract] [KnownType(typeof(SampleItem))] public class SampleClass { [DataMember] public System.Collections.ArrayList Items; public SampleClass() { Items = new System.Collections.ArrayList(); Items.Add(new SampleItem(12, "こんにちは")); } } public class MainClass { public static void Main() { string fileName = @"C:\test\test.xml"; //シリアル化するオブジェクト SampleClass obj = new SampleClass(); //普通にシリアル化できるようになる DataContractSerializer serializer = new DataContractSerializer(typeof(SampleClass)); XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = new System.Text.UTF8Encoding(false); XmlWriter xw = XmlWriter.Create(fileName, settings); serializer.WriteObject(xw, obj); xw.Close(); } }
上記のコードで作成されたXMLファイルの内容は、以下のようになります。
<?xml version="1.0" encoding="utf-8"?> <SampleClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/"> <Items xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <d2p1:anyType i:type="SampleItem"> <Message>こんにちは</Message> <Number>12</Number> </d2p1:anyType> </Items> </SampleClass>