在C#中,一切都是对象,所有的类都从System.Object派生。相对的,一切数组实例也都是对象,所有的数组类都在System.Array派生。而Array类是Serializable的,那么Voucher[]是否能够直接进行序列化呢,我们可以尝试另外一种序列化多个Voucher的方式,代码如下:
因为接口没有变化,因此可以用之前的NUnit测试方法,测试通过。因此,可以得出结论,如果类A能够被序列化,那么A[]也能被序列化。
NUnit测试方法序列化Voucher[]时生成的二进制文件内容如下:
为了比较两种序列化的方式,把多个对象依次序列化产生的文件内容列在下面:
采用序列化数组的方法产生的文件要比将多个对象依次序列化产生的文件要小得多。数组序列化时,Assembly的信息,Voucher class的信息,Voucher fields的信息都只需要一次输出,而将多个对象依次序列化时,相应的信息要为每一个对象输出。
除了类型信息之外,还有一个有意思的现象,"2005012900001"和"xingd"在数组序列化时只输出了一次,但NUnit的测试中是产生了两个Voucher对象的,虽然它们的voucherId和creator的值是一样的。.是不是因为值一样,所以才只输出一次呢。将测试方法修改如下:
输出的vouhcer.dat内容如下:
可以看到,两个Voucher对象的voucherId和creator都有输出了。但是,在这两种测试方法中,两个Voucher对象的createdTime都是分别输出的,但实际上它们应该具有相同的值。那么,是不是因为DateTime是值类型,而string是引用类型。NET中对字符串处理时,会产生一个内置的字符串池,具有相同值的字符串会引用值中的同一个对象。为了进一步了解,再对测试方法进行修改:
生成的文件内容如下:
明显的可以看出,只有一个Voucher对象产生了输出。在BinaryFormatter序列化过程中,似乎是首先生成要序列化对象的整个Graph,然后将涉及的对象一一序列化的。因此,不仅是数组中相同的对象避免重复输出,在序列化对象所引用的对象形成的Graph中,相同的对象只会输出一次。
通过本文的比较可以确定,应当优先考虑将集合类整体序列化,而不要自己将集合中的每一个元素依次序列化。
public void BatchSerialize(string filename, Voucher[] vouchers)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream fs = new FileStream(filename, FileMode.Create);
formatter.Serialize(fs, vouchers);
fs.Close();
}
public Voucher[] BatchDeserialize(string filename)
{
BinaryFormatter formatter = new BinaryFormatter();
Voucher[] vouchers = null;
FileStream fs = new FileStream(filename, FileMode.Open);
try
{
vouchers = (Voucher[])formatter.Deserialize(fs);
}
finally
{
fs.Close();
}
return vouchers;
}
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream fs = new FileStream(filename, FileMode.Create);
formatter.Serialize(fs, vouchers);
fs.Close();
}
public Voucher[] BatchDeserialize(string filename)
{
BinaryFormatter formatter = new BinaryFormatter();
Voucher[] vouchers = null;
FileStream fs = new FileStream(filename, FileMode.Open);
try
{
vouchers = (Voucher[])formatter.Deserialize(fs);
}
finally
{
fs.Close();
}
return vouchers;
}
因为接口没有变化,因此可以用之前的NUnit测试方法,测试通过。因此,可以得出结论,如果类A能够被序列化,那么A[]也能被序列化。
NUnit测试方法序列化Voucher[]时生成的二进制文件内容如下:
为了比较两种序列化的方式,把多个对象依次序列化产生的文件内容列在下面:
采用序列化数组的方法产生的文件要比将多个对象依次序列化产生的文件要小得多。数组序列化时,Assembly的信息,Voucher class的信息,Voucher fields的信息都只需要一次输出,而将多个对象依次序列化时,相应的信息要为每一个对象输出。
除了类型信息之外,还有一个有意思的现象,"2005012900001"和"xingd"在数组序列化时只输出了一次,但NUnit的测试中是产生了两个Voucher对象的,虽然它们的voucherId和creator的值是一样的。.是不是因为值一样,所以才只输出一次呢。将测试方法修改如下:
[Test]
public void TestSerializeVouchers()
{
Voucher[] vouchers = new Voucher[] {new Voucher("2005012900001", "xingd", DateTime.Now), new Voucher("2005012900002", "steven", DateTime.Now)};
VoucherSerializer serializer = new VoucherSerializer();
serializer.BatchSerialize("voucher.dat", vouchers);
}
public void TestSerializeVouchers()
{
Voucher[] vouchers = new Voucher[] {new Voucher("2005012900001", "xingd", DateTime.Now), new Voucher("2005012900002", "steven", DateTime.Now)};
VoucherSerializer serializer = new VoucherSerializer();
serializer.BatchSerialize("voucher.dat", vouchers);
}
输出的vouhcer.dat内容如下:
可以看到,两个Voucher对象的voucherId和creator都有输出了。但是,在这两种测试方法中,两个Voucher对象的createdTime都是分别输出的,但实际上它们应该具有相同的值。那么,是不是因为DateTime是值类型,而string是引用类型。NET中对字符串处理时,会产生一个内置的字符串池,具有相同值的字符串会引用值中的同一个对象。为了进一步了解,再对测试方法进行修改:
[Test]
public void TestSerializeVouchers()
{
Voucher voucher = new Voucher("2005012900001", "xingd", DateTime.Now);
Voucher[] vouchers = new Voucher[] {voucher, voucher};
VoucherSerializer serializer = new VoucherSerializer();
serializer.BatchSerialize("voucher.dat", vouchers);
}
public void TestSerializeVouchers()
{
Voucher voucher = new Voucher("2005012900001", "xingd", DateTime.Now);
Voucher[] vouchers = new Voucher[] {voucher, voucher};
VoucherSerializer serializer = new VoucherSerializer();
serializer.BatchSerialize("voucher.dat", vouchers);
}
生成的文件内容如下:
明显的可以看出,只有一个Voucher对象产生了输出。在BinaryFormatter序列化过程中,似乎是首先生成要序列化对象的整个Graph,然后将涉及的对象一一序列化的。因此,不仅是数组中相同的对象避免重复输出,在序列化对象所引用的对象形成的Graph中,相同的对象只会输出一次。
通过本文的比较可以确定,应当优先考虑将集合类整体序列化,而不要自己将集合中的每一个元素依次序列化。