一、概述

序列化是把对象转变成流。相反的过程就是反序列化。

哪些场合用到这项技术呢?

1. 把对象保存到本地,下次运行程序时恢复这个对象。

2. 把对象传送到网络的另一台终端上,然后在此终端还原这个对象。

3. 复制系统的粘帖板中,然后用快捷键Ctrl+V恢复这个对象。

常用的序列化流有Binary(二进制流),XML,SOAP。

二、序列化和反序列化使用事例:

这里我们把序列化和反序列化以功能类的形式展现:

 public class Serializer
{
//将类型序列化为字符串
public static string Serialize<T>(T t) where T : class
{
using(MemoryStream stream=new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, t);
return System.Text.Encoding.UTF8.GetString(stream.ToArray());
}
} //将类型序列化为文件
public static void SerializeToFile<T>(T t, string path, string fullName) where T : class
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string fullPath = string.Format(@"{0}\{1}", path, fullName);
using (FileStream stream = new FileStream(fullPath,FileMode.OpenOrCreate))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, t);
stream.Flush();
}
} //将类型序列化为文件
public static void SerializeToFileByXml<T>(T t, string path, string fullName) where T : class
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
} string fullPath = string.Format(@"{0}\{1}", path, fullName); using (FileStream stream = new FileStream(fullPath, FileMode.OpenOrCreate))
{
XmlSerializer formatter = new XmlSerializer(typeof(T));
formatter.Serialize(stream, t);
stream.Flush();
}
}
//将字符串反序列化为类型
public static TResult Deserialize<TResult>(string s) where TResult : class
{
byte[] bs = System.Text.Encoding.UTF8.GetBytes(s);
using (MemoryStream stream = new MemoryStream(bs))
{
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream) as TResult;
}
} //将文件反序列化为类型
public static TResult DeserializeFromFile<TResult>(string path) where TResult : class
{
using (FileStream stream = new FileStream(path,FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream) as TResult;
}
} //将xml文件反序列化为类型
public static TResult DeserializeFromFileByXml<TResult>(string path) where TResult : class
{
using (FileStream stream = new FileStream(path, FileMode.Open))
{
XmlSerializer formatter = new XmlSerializer(typeof(TResult)); ;
return formatter.Deserialize(stream) as TResult;
}
}
}

上面事例中的方法是以泛型方法实现的,其中附加了泛型约束,保证泛型安全。

序列化功能类有了下面我们建一个Book对象,用它来测试我们的功能类。

    [Serializable]
public class Book
{
[NonSerialized]
private string _bookPwd;
[field: NonSerialized]
public event EventHandler NameChanged;
private string _bookName;
private string _bookID;
public ArrayList alBookReader;
public string _bookPrice; public Book()
{
alBookReader = new ArrayList();
} public string BookName
{
get { return _bookName; }
set
{
if (NameChanged != null)
{
NameChanged(this, null);
}
_bookName = value;
}
} public void BookPwd(string pwd)
{
_bookPwd=pwd;
} public string BookID
{
get { return _bookID; }
set { _bookID = value; }
} public void SetBookPrice(string price)
{
_bookPrice = price;
} [OnDeserializedAttribute]
public void changeName(StreamingContext context)
{
this.BookName = "C#深入浅出";
} public void Write()
{
Console.WriteLine("Book ID:" + BookID);
Console.WriteLine("Book Name:" + BookName);
Console.WriteLine("Book Password:" + _bookPwd);
Console.WriteLine("Book Price:" + _bookPrice);
Console.WriteLine("Book Reader:");
for (int i = 0; i < alBookReader.Count; i++)
{
Console.WriteLine(alBookReader[i]);
}
}
}

关键介绍:
1.[Serializable]特性定义该类型可以被序列化;

2.[NonSerialized]定义某个属性不被序列化,即:内部成员被NonSerialized禁止序列化特性标记;

3.[field: NonSerialized]定义事件不被序列化;

4.[OnDeserializedAttribute]当它应用于某个方法时,会指定对象被反序列化后立即执行此方法。

5.[OnDeserializingAttribute]当它应用于某个方法时,会指定对象被反序列化时立即执行此方法。

6.[OnSerializedAttribute]如果将对象图应用于某个方法时,会指定在序列化该对象图后是否调用此方法。

7.[OnSerializingAttribute]当它应用于某个方法时,会指定在对象序列化前调用此方法。、

我们用控制台程序实现序列化和反序列化:

static void Main(string[] args)
{
string path = "c:\\Test\\";
Book book = new Book();
book.NameChanged += new EventHandler(make_NameChanged);
book.BookID = "2001";
book.alBookReader.Add("Abel");
book.alBookReader.Add("Tomson");
book.BookName = "敏捷无敌";
book.BookPwd("*****");
book.SetBookPrice("102.00");
//对象序列化
Serializer.SerializeToFileByXml<Book>(book, path, "book.txt");
//对象反序列化
Book anothorbookserialize = new Book();
anothorbookserialize = Serializer.DeserializeFromFileByXml<Book>(path + "book.txt");
anothorbookserialize.Write();
Console.ReadKey();
} static void make_NameChanged(object sender, EventArgs e)
{
Console.WriteLine("Name Changed");
}

我们的事例是调用XML序列化流文件形式,序列化执行后的文件如下:

<?xml version="1.0"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <alBookReader>
    <anyType xsi:type="xsd:string">Abel</anyType>
    <anyType xsi:type="xsd:string">Tomson</anyType>
  </alBookReader>
  <_bookPrice>102.00</_bookPrice>
  <BookName>敏捷无敌</BookName>
  <BookID>2001</BookID>
</Book>

反序列化输出如下:

Name Changed
Book ID:2001
Book Name:敏捷无敌
Book Password:
Book Price:102.00
Book Reader:
Abel
Tomson

结果分析:

[NonSerialized]Book Password属性在序列化XML文件中没有出现Book Password。

[field: NonSerialized]NameChanged事件,在序列化XML文件中没有出现NameChanged。

[OnDeserializedAttribute]changeName()方法,执行反序列化后没有立即执行changeName()方法,Book Name名称没有改变,需要通过Binary流形式才能成功执行方法。

    //序列化
Serializer.SerializeToFile<Book>(book, path, "book.txt");
//反序列化
anothorbookserialize = Serializer.DeserializeFromFile<Book>(path + "book.txt");

我们以XML流为例是为了更好的理解序列化和反序列化的执行过程,实际应用中多数以Binary流形式实现序列化和反序列化较多。

三、继承ISerializable接口更灵活的控制序列化过程:

  当以上Serializable特性无法满足复杂的序列化过程时就需要实现ISerializable接口了。

  以下是格式化器的工作流程:如果格式化器在序列化一个对象的时候,发现对象实现了ISerializable接口,那他会忽略类所有序列化特性,转而调用GetObjectData方法的一个SerializationInfo对象,方法内部负责该对象属性的添加。反序列化时调用该对象受保护带参数构造方法中的一个SerializationInfo对象,方法内部对象属性赋值。

下面我们实现ISerializable接口的子类型应负责父类型的序列化为例:

1.父类同样实现了ISerializable接口

[Serializable]
public class Person:ISerializable
{
public string Name{get;set;} public Person()
{ } protected Person(SerializationInfo info,StreamingContext context)
{
Name = info.GetString("Name");
} public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name",Name);
}
}
[Serializable]
public class Employee: Person , ISerializable
{
public int Salary{get;set;}

public Employee()
{ } protected Employee(SerializationInfo info, StreamingContext context)
{
Salary = info.GetInt32("Salary");
Name = info.GetString("Name");
} public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info,context);
info.AddValue("Salary", Salary);
}
}

注意:Employee中的GetObjectData方法覆盖了基类Person中的虚方法GetObjectData。

Employee employee = new Employee() { Name = "Abel", Salary=1220 };
BinarySerializer.SerializeToFile<Employee>(employee, strFile, "employee.txt");
employee = BinarySerializer.DeserializeFromFile<Employee>("c:\\Test\\employee.txt");
Console.WriteLine(employee.Name);
Console.WriteLine(employee.Salary);

2.若父类没有实现了ISerializable接口如何处理呢?

我们要实现继承ISerializable接口的Employee类的一个父类Person,Person没有实现ISerializable接口,序列化器没有默认去处理Person对象,只能由我们自己去做。

下面我们用具体实例实现:

   [Serializable]
public class Person
{
public string Name{get;set;} } [Serializable]
public class Employee: Person , ISerializable
{
public int Salary{get;set;} public Employee()
{ } protected Employee(SerializationInfo info, StreamingContext context)
{
Salary = info.GetInt32("Salary");
Name = info.GetString("Name");
} public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
info.AddValue("Salary", Salary);
}
}

在这此序列化学习中我们用到了事件、泛型和流文件的处理知识,通过序列化我们可以实现本地加载,远程还原对象。

得到了一个Serializer工具类,该工具类封装了序列化和反序列化的过程。

C# 序列化理解 2(转)的更多相关文章

  1. C# 序列化理解 1(转)

    序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制.其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方.    .NET框架提供了两种串行化的方式: ...

  2. 什么是Java序列化?如何实现序列化?

    一.什么是序列化: 序列化理解成“打碎”是可以的,不过在书本上的名词就是将对象转换成二进制. 二.在java中如何实现序列化: 首先我们要把准备要序列化类,实现 Serializabel接口 例如:我 ...

  3. JAVA 中进行网络通信时,通信的程序两端要传输的对象,不仅要序列化,而且这个对象所属的类的名字要完全一样,连包的名字都得一样

    如上图项目目录,这是一个简易的QQ,客户端登录的时候要传输用户信息到服务器验证,所以两端都会用到User类的对象,但一开始我在Server端的包名是com.qq.server.common,两端的报名 ...

  4. Java基础知识总结--反射

    反射:在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识.这个信息跟踪着每一个对象所属的类.虚拟机利用运行时类型信息选择相应的方法执行. Java反射机制是在系统运行状态 ...

  5. 05.DRF-Django REST framework 简介

    一.明确REST接口开发的核心任务 分析一下上节的案例,可以发现,在开发REST API接口时,视图中做的最主要有三件事: 将请求的数据(如JSON格式)转换为模型类对象 操作数据库 将模型类对象转换 ...

  6. java 的持久化和序列化的简单理解

    1.对象的持久化(Persistence) 对象持久化就是让对象的生存期超越使用对象的程序的运行期.将对象存储在可持久保存的存储介质上,在实际应用中,运用相应的对象持久化框架,将业务数据以对象的方式保 ...

  7. 对Java Serializable(序列化)的理解和总结

    我对Java Serializable(序列化)的理解和总结 博客分类: Java技术 JavaOSSocketCC++  1.序列化是干什么的?       简单说就是为了保存在内存中的各种对象的状 ...

  8. 理解Java对象序列化(二)

    关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制.在撰写本文时,既参考了Th ...

  9. Java Serializable(序列化)的理解和总结、具体实现过程(转)

    原文地址:http://www.apkbus.com/forum.php?mod=viewthread&tid=13576&fromuid=3402 Java Serializable ...

随机推荐

  1. 数据库 MySQL part1

    数据库介绍 数据库(database,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合.数据库中的数据按一定的数学模型组织.描述和存储,具有较小的冗余,较高的数据独立性和易扩展性,并可为各种 ...

  2. 暗影精灵3安装无线网卡驱动(ubuntu16.04)

    干货,无线网卡安装步骤: 1. 由于暗影精灵3的无线网卡较新,版本为Realtek Device b822,(查看命令为lspci | grep -i net,Ethernet controller代 ...

  3. Android stadio bug

    好生气啊,android stadio 有bug.自己的代码,一直没有生效,原来是stadio 的问题.只是因为我打开了增强模式,后来,buildToolVersion 改了之后,android st ...

  4. c++实验3类和对象

     实 验 3: part 1:验证 part 2:graph #include <iostream> #include "graph.h" using namespac ...

  5. 3、Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

  6. OrCAD生成网表

    1. 先选中.dsn设计文件 2. 按照默认设置,点击OK即可生成网表

  7. 创龙DSP6748开发板SYS/BIOS的LED闪烁-第2篇

    1. 作为1个456MHz的处理器,不跑个操作系统说不过去,直接打开工程\Demo\SYSBIOS\Application\GPIO_LED,主函数比较简单 // 创建任务 Task_create(t ...

  8. CWindowWnd类源码分析

    CWindowWnd代码在UIBase.h和UIBase.cpp文件里.主要实现的是一个基本窗口的创建与消息处理. 相关代码: 头文件: class UILIB_API CWindowWnd { pu ...

  9. Python目录链接

    第1章 就这么愉快的开始吧 课时1:我和python的第一次亲密接触 一.Python3的下载与安装 二.从IDIE启动Python 三.尝试点新的东西 四.为什么会这样? 五.课时01课后习题及答案 ...

  10. 学习人工智能的第六个月[深度学习[Deep Learning,DL]]

    这个月阅读了论文[Partial Adversarial Domain Adaptation-eccv18],文章着眼于源域标签空间包含目标域标签空间的场景,在域对抗神经网络的基础上提出了部分对抗域适 ...