Chủ nhật, ngày 4 tháng 12 năm 2016

.Net – Serialization và Deserialization trong C#

Ngày đăng: 12/3/2012, 13:54:37AM | Lượt xem: 7,487
Hot!

Serialization là một quá trình để chuyển đổi một cấu trúc dữ liệu hoặc đối tượng thành một định dạng có thể lưu trữ được (ví dụ như trong một file, bộ nhớ, hoặc vận chuyển thông qua mạng), sau đó nó có thể được phục hồi để trở lại trạng thái ban đầu trong một môi trường khác thông qua quá trình deserialization. Rất nhiều ngôn ngữ lập trình hiện nay hỗ trợ kĩ thuật này bao gồm C#, Java, Objective-C, Perl, Python, Ruby, PHP,… (Wikipedia).

Serialization là một quá trình để chuyển đổi một cấu trúc dữ liệu hoặc đối tượng thành một định dạng có thể lưu trữ được (ví dụ như trong một file, bộ nhớ, hoặc vận chuyển thông qua mạng), sau đó nó có thể được phục hồi để trở lại trạng thái ban đầu trong một môi trường khác thông qua quá trình deserialization. Rất nhiều ngôn ngữ lập trình hiện nay hỗ trợ kĩ thuật này bao gồm C#, Java, Objective-C, Perl, Python, Ruby, PHP,… (Wikipedia).

Serialization Process 

Attribute [Serializable] và [NonSerialized]

Mọi đối tượng muốn được serialize đều phải được khai báo kèm theo attribute [Serializable]. Ngoài ra, mọi kiểu dữ liệu được sử dụng trong đối tượng cũng phải tuân theo quy tắc này.

Nếu bạn muốn loại trừ một thành phần (method, field, property,…) không muốn được serialize, bạn có thể đánh dấu chúng bằng attribute [NonSerialized].

Thông thường hai attribute này là đủ để bạn thực hiện quá trình serialization và deserialization. Tuy nhiên nếu cần điều khiển thủ công hai quá trình này, bạn cần đến interface ISerializable. Ngược lại, nếu không quan tâm đến điều này bạn có thể bỏ qua phần ngay sau đây.

Interface ISerializable

Để điều khiển quá trình serialize một cách thủ công, bạn cần hiện thực interface ISerializable trong namespace System.Runtime.Serialization. Interface này chứa phương thức GetObjectData() mà quá trình serialize sẽ gọi đến khi được thực thi:

 
void GetObjectData(
         SerializationInfo info,
         StreamingContext context
)

Tham số SerializationInfo để lưu trữ thông tin đối tượng. Lớp này cung cấp các phương thức Add và Get để gán và lấy thông tin từ đối tượng.

Ngoài ra bạn cần cung cấp thêm một constructor của đối tượng với hai tham số tương tự phương thức GetObjectData() là SerializationInfo và StreamingContext dùng cho quá trình deserialize. Khi bạn hiện thực giao diện này thì attribute [NonSerialized] sẽ không có hiệu lực.

Ví dụ đơn giản cho lớp MyFile mà bạn có thể thực hiện kiểm tra với phương thức Main() được cung cấp ở phần cuối.

[Serializable]
public class MyFile:ISerializable
{
    public string Name;
    [NonSerialized]
    public long Length;

    public MyFile(string name,long length)
    {
        Name=name;
        Length=length;
    }

    private MyFile(SerializationInfo info, StreamingContext context)
    {
        Name=info.GetString("Name");
        Length=info.GetInt64("Length");
    }
    public override string ToString()
    {
        return string.Format("[MyFile Name={0}, Length={1}]", Name, Length);
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Name",Name,Name.GetType());
        info.AddValue("Length",Length,Length.GetType());
    }
}

Các loại formatter

Các formatter được sử dụng để serialize trong .Net đều được implement interface IFormatter trong namespace System.Runtime.Serialization, bao gồm BinaryFormatter và SoapFormatter. Interface này chỉ có hai phương thức là Serialize() và Deserialize()

-          BinaryFormatter: (namespace System.Runtime.Serialization.Formatters.Binary)

Serialize đối tượng thành một tập tin nhị phân.

-          SoapFormatter: (namespace System.Runtime.Serialization.Formatters.Soap)

Serialize đối tượng thành định dạng XML để truyền tải thông tin giữa các ứng dụng qua mạng thông qua giao thức HTTP. Do là dạng văn bản nên dung lượng dữ liệu tạo ra sẽ nặng hơn so với BinaryFormatter.

Note: Nếu bạn muốn một phương pháp Serialize để tạo file Xml thông thường, hãy tìm hiểu namespace System.Xml.Serialization.

Ví dụ minh họa

Để làm ví dụ, trước tiên tôi tạo ra hai lớp sau dùng để lưu trữ các file trong một folder. Hai class tương ứng là MyFolder và MyFile đều được đánh dấu với [Serializable].

[Serializable]
public class MyFolder
{
    public string Path;
    public IDictionary<string, MyFile> Files;

    public MyFolder(string path)
    {
        Files=new Dictionary<string, MyFile>();
        Path=path;
        foreach(var item in Directory.GetFiles(path))
        {
            FileInfo finfo=new FileInfo(item);
            Files.Add(finfo.Name,new MyFile(finfo.Name,finfo.Length));
        }
    }
    public bool ContainsFile(string name)
    {
        return Files.ContainsKey(name);
    }
}
[Serializable]
public class MyFile
{
    public string Name;
    public long Length;

    public MyFile(string name,long length)
    {
        Name=name;
        Length=length;
    }
    public override string ToString()
    {
        return string.Format("[MyFile Name={0}, Length={1}]", Name, Length);
    }
}

Tiếp đến ta cần hai phương thức để Serialize và Deserialize, hai phương thức này được viết chung để hỗ trợ cho mọi kiểu formatter implement từ IFormatter, các phương thức này được đặt trong lớp Y2Formatter:

private static void Serialize(string fileName, object data, IFormatter formatter)
{
    FileStream myStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);

    formatter.Serialize(myStream , data);

    myStream .Close();
}

private static T Deserialize<T>(string fileName, IFormatter formatter)
{
    FileStream myStream = new FileStream(fileName, FileMode.Open);

    T data= (T)formatter.Deserialize(myStream);

    myStream.Close();

    return data;
}

Cuối cùng cung cấp thêm các phương thức XXXSerialize() và XXXDeserialize() tương ứng cho từng kiểu formatter để đơn giản hóa lời gọi phương thức.

public static void BinSerialize(string fileName, object data)
{
    Serialize(fileName,data,new BinaryFormatter());
}

public static T BinDeserialize<T>(string fileName)
{
    return Deserialize<T>(fileName,new BinaryFormatter());
}

public static void SoapSerialize(string fileName, object data)
{
    Serialize(fileName,data,new SoapFormatter());
}

public static T SoapDeserialize<T>(string fileName)
{
    return Deserialize<T>(fileName,new SoapFormatter());
}

Phương thức Main để kiểm tra:

public static class Program
{
    private const string FILE_NAME=@"C:\data.xml";
    static void Main(string[] args)
    {
        // Test BinSerialize(), BinDeserialize()
        //
        // MyFolder firstFolder=new MyFolder(@"C:\Windows");
        // Y2Formatter.BinSerialize(FILE_NAME,firstFolder);
        // MyFolder secondFolder=Y2Formatter.BinDeserialize<MyFolder>(FILE_NAME);
        // foreach(var item in secondFolder.Files)
        //      Console.WriteLine(item.Value.Name);

        // Test SoapSerialize(), SoapDeserialize()
        //
        MyFile file=new MyFile("Fake.abc",10);
        Y2Formatter.SoapSerialize(FILE_NAME,file);

        MyFile file2=Y2Formatter.SoapDeserialize<MyFile>(FILE_NAME);

        Console.WriteLine(file2);

        Console.Read();
    }
}

Output:

[MyFile Name=Fake.abc, Length=10]

Bạn có thể thấy file data.xml kết quả của ví dụ trên với nội dung sau:

<SOAP-ENV:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:clr=”http://schemas.microsoft.com/soap/encoding/clr/1.0″ SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>

<SOAP-ENV:Body>

<a1:MyFile id=”ref-1″ xmlns:a1=”http://schemas.microsoft.com/clr/nsassem/SerializationExample/AppDomainExample%2C%20Version%3D1.0.4170.15013%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull”>
<Name id=”ref-3″>Fake.abc</Name>
<Length>10</Length>
</a1:MyFile>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Mã nguồn hoàn chỉnh

Program.cs:

using System;
using System.Collections.Generic;
using System.IO;

namespace SerializationExample{

    [Serializable]
    public class MyFolder
    {
        public string Path;
        public IDictionary<string, MyFile> Files;

        public MyFolder(string path)
        {
            Files=new Dictionary<string, MyFile>();
            Path=path;
            foreach(var item in Directory.GetFiles(path))
            {
                FileInfo finfo=new FileInfo(item);
                Files.Add(finfo.Name,new MyFile(finfo.Name,finfo.Length));
            }
        }
        public bool ContainsFile(string name)
        {
            return Files.ContainsKey(name);
        }
    }
    [Serializable]
    public class MyFile
    {
        public string Name;
        public long Length;

        public MyFile(string name,long length)
        {
            Name=name;
            Length=length;
        }
        public override string ToString()
        {
            return string.Format("[MyFile Name={0}, Length={1}]", Name, Length);
        }
    }

    public static class Program
    {
        private const string FILE_NAME=@"C:\data.xml";
        static void Main(string[] args)
        {
            // Test BinSerialize(), BinDeserialize()
            //
            // MyFolder firstFolder=new MyFolder(@"C:\Windows");
            // Y2Formatter.BinSerialize(FILE_NAME,firstFolder);
            // MyFolder secondFolder=Y2Formatter.BinDeserialize<MyFolder>(FILE_NAME);
            // foreach(var item in secondFolder.Files)
            //      Console.WriteLine(item.Value.Name);

            // Test SoapSerialize(), SoapDeserialize()
            //
            MyFile file=new MyFile("Fake.abc",10);
            Y2Formatter.SoapSerialize(FILE_NAME,file);

            MyFile file2=Y2Formatter.SoapDeserialize<MyFile>(FILE_NAME);

            Console.WriteLine(file2);

            Console.Read();
        }
    }
}

Y2Formatter.cs:

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

namespace SerializationExample
{
    public class Y2Formatter
    {
        public static void BinSerialize(string fileName, object data)
        {
            Serialize(fileName,data,new BinaryFormatter());
        }
        public static T BinDeserialize<T>(string fileName)
        {
            return Deserialize<T>(fileName,new BinaryFormatter());
        }
        public static void SoapSerialize(string fileName, object data)
        {
            Serialize(fileName,data,new SoapFormatter());
        }
        public static T SoapDeserialize<T>(string fileName)
        {
            return Deserialize<T>(fileName,new SoapFormatter());
        }

        private static void Serialize(string fileName, object data, IFormatter formatter)
        {
            FileStream myStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);

            formatter.Serialize(myStream , data);

            myStream .Close();
        }
        private static T Deserialize<T>(string fileName, IFormatter formatter)
        {
            FileStream myStream = new FileStream(fileName, FileMode.Open);

            T data= (T)formatter.Deserialize(myStream);

            myStream.Close();

            return data;
        }
    }
}

http://yinyangit.wordpress.com

 Chia sẻ qua: 
Hot!
Ý kiến bạn đọc

These items will be permanently deleted and cannot be recovered. Are you sure?

Gallery

image

Maecenas viverra rutrum pulvinar

Maecenas viverra rutrum pulvinar! Aenean vehicula nulla sit amet metus aliquam et malesuada risus aliquet. Vestibulum rhoncus, dolor sit amet venenatis porta, metus purus sagittis nisl, sodales volutpat elit lorem…

Read more

Text Links

Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
Copyright © 2011 - 2012 vietshare.vn by phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.