On serialization and deserialization in. Net

Time:2021-2-23

Serialization and deserialization are often heard and used by all of us. However, some people may not know why. Net has such a thing and how. Net frameword can implement such a mechanism for us. Here I also briefly talk about my understanding of serialization and deserialization.

1、 What is serialization and deserialization

Serialization is the process of converting an object into a byte stream so that it can be easily saved in a disk file or database. Deserialization is the reverse process of serialization, which is the process of converting a byte stream back to the original object.

But why do we need mechanisms like serialization and deserialization? This problem also involves the use of serialization and deserialization,

The main uses of serialization are:

  • Save the state of the application in a disk file or database, and restore the state the next time the application runs. For example, Asp.net Serialization and deserialization are used to save and recover session state.
  • A group of objects can be easily copied to the Windows Forms clipboard and pasted back to the same or another application.
  • Send objects by value from one application domain to another

And if the object sequence into a byte stream in memory, you can use some other technology to process data, such as data encryption and compression.

2、 Serialization and deserialization are easy to use

The. Net framework provides two serialization methods:

  • Binary Serialization
  • XML and soap serialization

Simple use of serialization and deserialization:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Serializable
{
  [Serializable]
  public class Person
  {
    public string personName;

    [NonSerialized]
    public string personHeight;

    private int personAge;
    public int PersonAge
    {
      get { return personAge; }
      set { personAge = value; }
    }

    public void Write()
    {
      Console.WriteLine("Person Name: "+personName);
      Console.WriteLine("Person Height: " +personHeight);
      Console.WriteLine("Person Age: "+ personAge);
    }

  }
  class Program
  {
    static void Main(string[] args)
    {
      Person person = new Person();
      person.personName = "Jerry";
      person.personHeight = "175CM";
      person.PersonAge = 22;
      Stream stream = Serialize(person);

      //All reset for demonstration purposes
      stream.Position = 0;
      person = null;

      person = Deserialize(stream);
      person.Write();
      Console.Read();

    }
    private static MemoryStream Serialize(Person person)
    {
      MemoryStream stream = new MemoryStream();

      //Constructing binary serialization formatter
      BinaryFormatter binaryFormatter = new BinaryFormatter();
      //Tells the serializer to serialize the object into a stream
      binaryFormatter.Serialize(stream, person);

      return stream;

    }

    private static Person Deserialize(Stream stream)
    {
      BinaryFormatter binaryFormatter = new BinaryFormatter();
      return (Person)binaryFormatter.Deserialize(stream);
    }

  }
}

Mainly call System.Runtime.Serialization . Formatters.Binary The binnaryformatter class under the namespace is used for serialization and deserialization, and the result screenshot after calling deserialization is as follows:

It can be seen that all members except the non serialized tag can be serialized. Note that this property can only be applied to fields in one type and will be inherited by derived types.

The serialization and deserialization of soap and XML are similar to the above. Just change the formatter. I won’t list them here.

3、 Control serialization and deserialization

There are two ways to achieve control serialization and deserialization:

  • Through the properties of onserializing, onserialized, ondeserializing, ondeserialized, nonserialized and optionalfield
  • realization System.Runtime.Serialization . iserializable interface

The first way is to control the serialization and deserialization code

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace ControlSerialization
{
  [Serializable]
  public class Circle
  {
    Private double radius; // radius
    [NonSerialized]
    Public double area; // area

    public Circle(double inputradiu)
    {
      radius = inputradiu;
      area = Math.PI * radius * radius;
    }

    [OnDeserialized]
    private void OnDeserialized(StreamingContext context)
    {
      area = Math.PI * radius * radius;
    }

    public void Write()
    {
      Console.WriteLine("Radius is: " + radius);
      Console.WriteLine("Area is: " + area);
    }
  }
  class Program
  {

    static void Main(string[] args)
    {
      Circle c = new Circle(10);
      MemoryStream stream =new MemoryStream();
      BinaryFormatter formatter = new BinaryFormatter();
      //To serialize an object into a memory stream, you can use the System.IO.Stream An object of any type derived from an abstract class. Here I use the memorystream type.
      formatter.Serialize(stream,c);
      stream.Position = 0;
      c = null;
      c = (Circle)formatter.Deserialize(stream);
      c.Write();
      Console.Read();

    }
  }
}

The running results are as follows

Note: if the ondeserialized attribute is commented out, the value of the area field is 0, because the area field is not serialized into the stream.

In the above objects that need to be serialized, the formatter will only serialize the value of the radius field of the object. The value in the area field will not be serialized because the nonserializedattribute attribute has been applied to the field. When we build a circle object with code like circle C = new circle (10), internally, the area will set a value of 314.159. When the object is serialized, only the value (10) of the radius field is written to the stream, But when it is deserialized into a circle object, the value of its area field is initialized to 0 instead of a value of about 314.159. To solve this problem, a custom method is used to apply the ondeserializedattribute attribute. At this time, the execution process is as follows: every time an instance of a type is deserialized, the formatter will check whether a method applying the attribute is defined in the type. If so, the method will be called. When the method is called, all serializable fields will be set correctly. In addition to the custom attribute ondeserializedattribute, system.Runtime.Serialization The namespace also defines custom attributes such as onserializingattribute, onserializingattribute and ondeserializingattribute.

Implement iserializable interface to control serialization and deserialization code

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;

namespace ControlSerilization2
{
  [Serializable]
  public class MyObject : ISerializable
  {
    public int n1;
    public intn2;

    [NonSerialized]
    public String str;

    public MyObject()
    {
    }

    protected MyObject(SerializationInfo info, StreamingContext context)
    {
      n1 = info.GetInt32("i");
      n2 = info.GetInt32("j");
      str = info.GetString("k");
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
      info.AddValue("i", n1);
      info.AddValue("j", n2);
      info.AddValue("k", str);
    }

    public void Write()
    {
      Console.WriteLine("n1 is: " + n1);
      Console.WriteLine("n2 is: " + n2);
      Console.WriteLine("str is: " + str);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      MyObject obj = new MyObject();
      obj.n1 = 2;
      obj.n2 = 3;
      obj.str = "Jeffy";
      MemoryStream stream = new MemoryStream();
      BinaryFormatter formatter = new BinaryFormatter();
      //To serialize an object into a memory stream, you can use the System.IO.Stream An object of any type derived from an abstract class. Here I use the memorystream type.
      formatter.Serialize(stream, obj);
      stream.Position = 0; 
      obj = null;
      obj = (MyObject)formatter.Deserialize(stream);
      obj.Write();
      Console.Read();
    }
  }
}

The results were as follows

The execution process is as follows: when the formatter serializes objects, it will check each object. If it is found that the type of an object implements the iserializable interface, the formatter will ignore all custom attributes and construct a new one instead System.Runtime.Serialization . serializationinfo object, which contains the collection of values to actually serialize for the object. After the serializationinfo object is constructed and initialized, the formatter calls the getobjectdata method of the type and passes it a reference to the serializationinfo object. The getobjectdata method is responsible for determining what information is needed to serialize the object, and adding this information to the serializationinfo object. It calls the addvalue method to add each required data, so as to add the serializationinfo object After all the necessary serialization information is returned to the formatter, the formatter gets all the values added to the serializationinfo object and serializes them into the stream. When deserializing, the formatter extracts an object from the stream and allocates memory for the new object. Initially, all the fields of the object are set to 0 or null, Then, the formatter checks whether the type implements the iserializable interface. If this interface exists, the formatter attempts to call a special constructor whose parameters are exactly the same as those of the getobjectdata method.

4、 How does the formatter serialize and deserialize

It can be seen from the above analysis that the formatter is mainly working to serialize and deserialize. However, the following is how the formatter serializes an object with serializable attribute applied.

  1. The formatter calls the getserializable members method of formatterservices: public static memberinfo [] getserializable members (type, streamingcontext context); this method obtains the public and private implementation fields of the type (except the fields marked with nonserializedattributee attribute) by transmitting. Method returns an array of memberinfo objects, where each element corresponds to a serializable instance field.
  2. Object is serialized, System.Reflection.MemberInfo Object array is passed to the static method getobjectdata of formatterservices: public static object [] getobjectdata (object obj, memberinfo [] members). This method returns an object array, in which each element identifies the value of a segment in the serialized object.
  3. The formatter writes the full name of the assembly ID and type to the stream.
  4. The formatter then iterates through the elements in the two arrays and writes the name and value of each member to the stream.

The next step is to explain how the formatter automatically deserializes an object to which the SerializableAttribute attribute is applied.

  1. The formatter reads the assembly ID and full type name from the stream.
  2. The formatter calls the static method getuninitialized object of formatterservices: public static object getuninitialized object (type Ttype); this method allocates memory for a new object, but does not call the constructor for the object. However, all fields of the object are initialized to 0 or null
  3. The formatter now constructs and initializes an array of memberinfo, and calls the getserializable members method of formatterservices. This method returns a set of serialized fields that need to be deserialized.
  4. The formatter creates and initializes an object array based on the data contained in the stream.
  5. Pass the reference to the newly allocated object, memberinfo array and parallel object array to the static method populateobjectmembers of formatterservices

Public static object populateobjectmembers (object obj, memberinfo [] members, object [] data); this method traverses the array and initializes each field to its corresponding value.

Note: the part of formatting how to serialize and deserialize objects is extracted from CLR via C # (Third Edition). It is written here to let beginners further understand the work of the formatter in the process of serialization and deserialization.

Writing here, this article about serialization and de sequence is finally over. I hope it will be helpful for my future review and friends in the garden.

The above is the detailed content of serialization and deserialization in. Net. For more information about. Net serialization and deserialization, please pay attention to other related articles in developer!