MCP試験 70-483 Programming in C# の学習材料。
目次はこちら
4-4 データをシリアル化および逆シリアル化する
シリアル化(Serialization)
シリアル化(Serialize)とは、メモリ内のオブジェクトをバイト列やテキストに変換することをいう。逆に、そのバイト列やテキストをオブジェクトに変換することをで逆シリアル化(Deserialize)という。オブジェクトをファイルに保存したり、ネットワーク越しの別のプログラムに渡したいときに必要なプロセス。このシリアル化・逆シリアル化するプログラムのことをシリアライザ(Serializer)という。
※ここで紹介するシリアライザよりも何倍も高速で使いやすいシリアライザが世に出回ってるので、.NET標準ライブラリ縛りプレイをしない限りは使うことは無いかもしれない。
XmlSerializer
オブジェクトを XML に変換するシリアライザ。昔ながらの XML-RPC を使うときにお世話になるかも。
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int tmpValue;
}
void Main()
{
Product item = new Product()
{
Id = 1,
Name = "CPU",
tmpValue = 123
};
string serializedData = null;
// Serialize
{
XmlSerializer xs = new XmlSerializer(typeof(Product));
StringWriter sw = new StringWriter();
xs.Serialize(sw, item);
serializedData = sw.ToString();
}
Console.WriteLine(serializedData);
// Deserialize
{
XmlSerializer xs = new XmlSerializer(typeof(Product));
Product deserilizedObject = xs.Deserialize(new StringReader(serializedData)) as Product;
}
}
serializedData の中身
<?xml version="1.0" encoding="utf-16"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<tmpValue>123</tmpValue>
<Id>1</Id>
<Name>CPU</Name>
</Product>
上記サンプルでは TextReader/Writer に(デ)シリアライズしているが、Stream や XmlReader/Writer を使うこともできる。
XmlSerializerで使うAttribute
XML をシリアライズまたはシリアライスする際、特定のプロパティだけシリアライズしたくなかったり XML Element ではなく Attribute にしたかったりする場合は、対象プロパティに属性を付けると制御できる。
XmlSerializerに使用できる属性例
- XmlIgnore
- XmlRoot
- XmlAttirbute
- XmlElement("xmltag")
- XmlText
- XmlArray
- XmlArrayItem
public class Product
{
[XmlAttribute]
public int Id { get; set; }
[XmlAttribute]
public string Name { get; set; }
[XmlIgnore]
public int tmpValue;
}
<?xml version="1.0" encoding="utf-16"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="1" Name="CPU" />
BinaryFormatter
XML はサイズがでかい。BinaryFormatter を使うと、比較的小さいサイズのバイナリにシリアライズできる。
[Serializable]
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[NonSerialized]
public int tmpValue;
}
void Main()
{
Product item = new Product()
{
Id = 1,
Name = "CPU",
tmpValue = 123
};
byte[] serializedData = null;
// Serialize
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream mem = new MemoryStream();
bf.Serialize(mem, item);
serializedData = mem.ToArray();
}
// Deserialize
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream mem = new MemoryStream(serializedData);
Product deserilizedObject = bf.Deserialize(mem) as Product;
}
}
serializedData の中身
00000000 00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00 .....ÿÿÿÿ.......
00000010 00 0C 02 00 00 00 43 71 75 65 72 79 5F 6E 63 77 ......Cquery_ncw
00000020 77 6E 6E 2C 20 56 65 72 73 69 6F 6E 3D 30 2E 30 wnn, Version=0.0
00000030 2E 30 2E 30 2C 20 43 75 6C 74 75 72 65 3D 6E 65 .0.0, Culture=ne
00000040 75 74 72 61 6C 2C 20 50 75 62 6C 69 63 4B 65 79 utral, PublicKey
00000050 54 6F 6B 65 6E 3D 6E 75 6C 6C 05 01 00 00 00 11 Token=null......
00000060 55 73 65 72 51 75 65 72 79 2B 50 72 6F 64 75 63 UserQuery+Produc
00000070 74 02 00 00 00 13 3C 49 64 3E 6B 5F 5F 42 61 63 t.....<Id>k__Bac
00000080 6B 69 6E 67 46 69 65 6C 64 15 3C 4E 61 6D 65 3E kingField.<Name>
00000090 6B 5F 5F 42 61 63 6B 69 6E 67 46 69 65 6C 64 00 k__BackingField.
000000A0 01 08 02 00 00 00 01 00 00 00 06 03 00 00 00 03 ................
000000B0 43 50 55 0B CPU.
BinarySerializer で使う属性
- Serializable: シリアライズしたいクラスに付ける(付けなければならない)
- NotSerialized: シリアライズしたくないプロパティ、フィールドに付ける
JavaScriptSerializer
JSON にシリアライズ。使うにはアセンブリ System.Web.Extensions をプロジェクトの参照に追加する。
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int tmpValue;
}
void Main()
{
Product item = new Product()
{
Id = 1,
Name = "CPU",
tmpValue = 123
};
string serializedData = null;
// Serialize
{
JavaScriptSerializer js = new JavaScriptSerializer();
serializedData = js.Serialize(item);
}
Console.WriteLine(serializedData);
// Deserialize
{
JavaScriptSerializer js = new JavaScriptSerializer();
Product deserilizedObject = js.Deserialize<Product>(serializedData);
}
}
serializedData の中身
{"tmpValue":123,"Id":1,"Name":"CPU"}
JavaScriptSerializer で使う属性
- ScriptIgnore: シリアライズしたくないプロパティ、フィールドに付ける
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[ScriptIgnoreAttribute]
public int tmpValue;
}
{"Id":1,"Name":"CPU"}
DataContractSerializer
XML シリアライザその2。主に WCF で使われる。使うにはアセンブリ System.Runtime.Serialization をプロジェクトの参照に追加する。
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int tmpValue;
}
void Main()
{
Product item = new Product()
{
Id = 1,
Name = "CPU",
tmpValue = 123
};
byte[] serializedData = null;
// Serialize
{
DataContractSerializer ds = new DataContractSerializer(typeof(Product));
MemoryStream mem = new MemoryStream();
ds.WriteObject(mem, item);
serializedData = mem.ToArray();
}
Console.WriteLine(Encoding.UTF8.GetString(serializedData));
// Deserialize
{
DataContractSerializer bf = new DataContractSerializer(typeof(Product));
MemoryStream mem = new MemoryStream(serializedData);
Product deserilizedObject = bf.ReadObject(mem) as Product;
}
}
serializedData の中身
<UserQuery.Product xmlns="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Id>1</Id><Name>CPU</Name><tmpValue>123</tmpValue></UserQuery.Product>
上記サンプルでは Stream に(デ)シリアライズしているが、XmlReader/Writer, XmlDictionaryReader/Writer を使うこともできる。
DataContractSerializer で使う属性
- DataContract: シリアライズしたいクラスに付ける
- DataMember: シリアライズしたいプロパティ、フィールドに付ける
- IgnoreDataMember: シリアライズしたくないプロパティ、フィールドに付ける
[DataContract]
public class Product
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[IgnoreDataMember]
public int tmpValue;
}
<UserQuery.Product xmlns="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Id>1</Id><Name>CPU</Name></UserQuery.Product>
DataContractJsonSerializer
DataContractSerializer が XML なのに対し、こちらは JSON. 使い方は全く同じ。
[DataContract]
public class Product
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[IgnoreDataMember]
public int tmpValue;
}
void Main()
{
Product item = new Product()
{
Id = 1,
Name = "CPU",
tmpValue = 123
};
byte[] serializedData = null;
// Serialize
{
DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(Product));
MemoryStream mem = new MemoryStream();
ds.WriteObject(mem, item);
serializedData = mem.ToArray();
}
Console.WriteLine(Encoding.UTF8.GetString(serializedData));
// Deserialize
{
DataContractJsonSerializer bf = new DataContractJsonSerializer(typeof(Product));
MemoryStream mem = new MemoryStream(serializedData);
Product deserilizedObject = bf.ReadObject(mem) as Product;
}
}
serializedData の中身
{"Id":1,"Name":"CPU"}
その他覚えておいた方がよさそうなキーワード
- ISerializable, IXmlSerializable
- OnSerializing, OnSerialized, OnDeserializing, OnDeserialized
- NetDataContractSerializer
リソース
Quiz
- XmlSerializer, BinarySerializer, JavaScriptSerializer, DataContract(Json)Serializer それぞれのシリアライザで使用する Attribute とインタフェースを整理しろ
- 下記の XML を Company オブジェクトに逆シリアル化できるように Company クラスを変更しろ。
<company>
<employee id="1" name="suzuki" />
<employee id="2" name="sato" />
<employee id="3" name="tanaka" />
<divisions>
<division>soumu</division>
<division>jinji</division>
</divisions>
</company>
public class Company
{
public Employee[] Employees { get; set; }
public Division[] Divisions { get; set; }
}