When voucher [] vouchers is serialized, we can see that the Assembly and type information is generated only once. However, if vouchers contains instances of classes derived from voucher, that is to say, when vouchers is a multi-state array, what is the situation. If binnaryformatter stores static data, the object cannot be completely restored during deserialization. On the other hand, because the parameters of the binaryformatter. serialize method are of the object type, binaryformatter should save the dynamic type of the object. To verify this conjecture, billvoucher is derived from the voucher class.
Billvoucher indicates the credential generated from the document. It needs to track the original document. The billvoucher class is defined as follows:
Namespace Generalledger
{
Public Class Billvoucher: voucher
{
Private String Billid;
Public Billvoucher ( String Billid, String Voucherid, String Creator, datetime createtime ): Base (Voucherid, creator, createtime)
{
This. Billid=Billid;
}
Public String Billid
{
Get
{
ReturnBillid;
}
}
}
}
Note that billvoucher does not add serializableattribute because some attributes can be inherited from the base class. So can serializableattribute be inherited? Use nunit to add the Test method:
[Test]
Public Void Testserializebillvoucher ()
{
Billvoucher voucher = New Billvoucher ( " 2005020400001 " , " 2005012900001 " , " Xingd " , Datetime. Now );
Voucherserializer serializer = New Voucherserializer ();
Serializer. serialize ( " Voucher. dat " , Voucher );
}
Run nunit to test and report an error. Will it be because the derived class has an additional field? Comments The billid temporarily and report the same error during the test. We can see that,Serializableattribute must be added to classes that support binaryformatter serialization. Even its base classes support binaryformatter serialization.After adding serializableattribute to billvoucher, the test passes.
What happens if the base class does not support serialization and the derived class has added serializableattribute? In actual application, it should not be allowed. Otherwise, it means that any class that can be derived can be indirectly serialized. For further verification, comment out the serializableattribute of the voucher class. Run nunit test testserializebillvoucher. The error message is as follows:
Generalledger. vouchertest. Failed: system. runtime. serialization. serializationexception: The type generalledger. Voucher in assembly voucher, version = enabled, culture = neutral, publickeytoken = NULL is not marked as serializable.
The error message clearly indicates that the class voucher is not marked as serializable.
Add the serializableattribute of voucher. Next, we will test the multi-state array. Modify testserializevouchers and testdeserializevouchers as follows:
[Test]
Public Void Testserializevouchers ()
{
Voucher [] vouchers = New Voucher [] { New Voucher ( " 2005012900001 " , " Xingd " , Datetime. Now ), New Billvoucher ( " 2005020400001 " , " 2005012900001 " , " Xingd " , Datetime. Now )} ;
Voucherserializer serializer = New Voucherserializer ();
Serializer. batchserialize ( " Voucher. dat " , Vouchers );
}
[Test]
Public Void Testdeserializevouchers ()
{
Voucherserializer serializer = New Voucherserializer ();
Voucher [] vouchers = Serializer. batchdeserialize ( " Voucher. dat " );
Assert. areequal (vouchers. length, 2 );
Assert. areequal (vouchers [ 0 ]. Voucherid, " 2005012900001 " );
Assert. areequal (vouchers [ 0 ]. Creator, " Xingd " );
Assert. areequal (vouchers [ 1 ]. GetType (), Typeof (Billvoucher ));
Assert. areequal (billvoucher) Vouchers [ 1 ]). Billid, " 2005020400001 " );
Assert. areequal (vouchers [ 1 ]. Voucherid, " 2005012900001 " );
Assert. areequal (vouchers [ 1 ]. Creator, " Xingd " );
}
After running, both tests pass. The generated voucher. dat content is as follows:
Based on voucher. Data, we can draw the following conclusions:
- Binaryformatter serialization is based on the object's dynamic type.
- When a derived class is serialized, the field of the base class is identified by base + field.
- During binaryformatter serialization of an object, only one output containing assembly information is generated for the same assembly in the graph formed by the object referenced by the object, only one output containing the type information is generated for the same type.
Interestingly, there is a seemingly redundant generalledger in the line 00000060. the voucher string is used to record the static type information of vouchers, that is, voucher []. The type information of voucher [] may be composed of the type information of voucher and an array identifier. When we analyze the file format generated during the serialization implementation process, we will verify this guess. If you are interested, you can verify it yourself.