Analyze problems
In many other programming languages (such as C ++), the process of serialization and deserialization often requires programmers to write code manually. The serializable feature provided by. Net helps programmers easily declare a serializable type. However, convenience often implies a lack of flexibility. Many times, due to business logic requirements, programmers often need to take the initiative to control the serialization and deserialization processes. NET provides the iserializable interface to meet custom serialization requirements.
To implement custom serialization and deserialization, the programmer needs to implement the iserializable interface and provide a specific method for constructing objects in deserialization. The following code shows the type model of custom serialization and deserialization:
Class myobject: iserializable {protected myobject (serializationinfo info, streamingcontext context) {// implement deserialization} Public Virtual void getobjectdata (serializationinfo info, streamingcontext context) {// implement serialization }}
As you can see, the specific deserialization constructor may not be a public constructor. In fact, the accessible level of the constructor does not affect deserialization. programmers can define it as private and protected as needed. Generally, due to the security relationship, this constructor will not be declared as public. This is also true. the net team did not design deserialization as implemented through interfaces. Getobjectdata and special constructor both accept two parameters. Parameters of the serializationinfo type are used in a hash table to store the content of the entire object through key/value pairs, the streamingcontext type parameter includes the current status of the stream. The programmer can determine whether to serialize or deserialize the type object based on this parameter.
If the base class implements the iserializable interface, the derived type must implement deserialization constructor for its own members, and override the getobjectdata method in the base class. The following code provides a specific instance.
Using system; using system. text; using system. runtime. serialization; using system. runtime. serialization. formatters. binary; using system. io; namespace testcustomize {// first write a type to be serialized and deserialized. Note that this type will be inherited by other types [serializable] class myobject: iserializable {private int _ Myint; [nonserialized] private string _ mystring; Public myobject (int I, string s) {_ Myint = I; _ mystring = s;} public override string Tostring () {return New stringbuilder (). appendformat ("INTEGER: {0} \ r \ n string: {1} \ r \ n", _ Myint. tostring (), _ mystring ). tostring () ;}// implement custom deserialization of protected myobject (serializationinfo info, streamingcontext context) {// read content from the serializationinfo structure _ Myint = info. getint32 ("myobjectint"); _ mystring = info. getstring ("myobjectstring");} // implement custom serialization Public Virtual void getobjectdata (serializationinfo info, streaming Context context) {// write the serializationinfo structure info. addvalue ("myobjectint", _ Myint); info. addvalue ("myobjectstring", _ mystring) ;}// compile a subclass that inherits this type and add a private member variable. Subclasses must be responsible for serialization and deserialization of their own added members. [Serializable] class myobjectson: myobject {private string _ sonstring; Public myobjectson (int I, string S): Base (I, S) {_ sonstring = s ;} public override string tostring () {return New stringbuilder (). the string of the appendformat ("{0} subclass is: {1} \ r \ n", base. tostring (), _ sonstring ). tostring ();} // implement deserialization. It is only responsible for protected myobjectson (serializationinfo info, streamingcontext context): Base (Info, context) {_ Sonst Ring = info. getstring ("myobjectsonstring");} // implement serialization. It is only responsible for public override void getobjectdata (serializationinfo info, streamingcontext context) {base. getobjectdata (Info, context); info. addvalue ("myobjectsonstring", _ sonstring) ;}// finally write the entry method to serialize and deserialize these two types of objects. Class customizeserialization {// main method, test custom serialization and deserialization static void main () {myobjectson OBJ = new myobjectson (10, "I am a string"); console. writeline ("initial object: {0}", OBJ); byte [] DATA = serialize (OBJ); console. writeline ("after serialization and deserialization:"); console. writeline (deserialize (data); console. read ();} // serialize object static byte [] serialize (myobjectson OBJ) {iformatter formatter = new binaryformatter (); Using (memorystream MS = new memorystream () {formatter. serialized (MS, OBJ); Return Ms. toarray () ;}// deserialization object static myobjectson deserialize (byte [] bytes) {iformatter formatter = new binaryformatter (); Using (memorystream MS = new memorystream (bytes )) {return formatter. deserialize (MS) as myobjectson ;}}}}
Because the serialization and deserialization are manually controlled, the serialization of all members of the type is realized, and all types of objects are completely restored after serialization and deserialization, includes members who have declared the nonserialized feature. The following is the code execution result.
Note:
To implement serialization and deserialization of subclasses, you need to call the serialization and deserialization of the base class. Otherwise, the object cannot be successfully serialized or deserialized.
Answer
The getobjectdata method in the iserialization interface can be used to implement custom serialization, while the deserialization process can be customized by adding a constructor with the serializationinfo and streamingcontext parameters.