.NET序列化的一点技巧
介绍
序列化是将对象状态转换为可保持或传输的形式的过程。序列化的补集是反序列化,后者将流转换为对象。这两个过程一起保证数据易于存储和传输。
.NET Framework 提供了两个序列化技术:
二进制序列化保持类型保真,这对于多次调用应用程序时保持对象状态非常有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象。您可以将对象序列化到流、磁盘、内存和网络等。远程处理使用序列化,“按值”在计算机或应用程序域之间传递对象。
XML 序列化只序列化公共属性和字段,并且不保持类型保真。当您希望提供或使用数据而不限制使用该数据的应用程序时,这一点非常有用。由于 XML 是开放式的标准,因此它对于通过 Web 共享数据来说是一个理想选择。SOAP 同样是开放式的标准,这使它也成为一个理想选择。
详细
具体命名空间:
System.Runtime.Serialization
包含可用于序列化和反序列化对象的类。(包括System.Runtime.Serialization.Formatters.Binary.BinaryFormatter,还有WCF中用到的DataContractAttribute, DataMemberAttribute)
System.Xml.Serialization
包含可用于将对象序列化为 XML 格式的文档或流的类。
WCF大家很熟悉,一般的书籍都对基础的东西有很多内容的讲解,这里就对非WCF的一些序列化技巧抛个砖。
一:序列化标记
需要序列化:[Serializable]也可以写成[SerializableAttribute]
特性“Serializable”只在“class, struct, enum, delegate”声明中有效。所以只能在类,结构体等上面标记。
不需要序列化:[NonSerialized]也可以写成[NonSerializedAttribute]
特性“NonSerialized”只在“field”声明中有效。所以只能在字段上标记,连属性器都不行。
二:特殊情况:
事件的标记:
[field: NonSerializedAttribute()],需要加入field标记。
属性的标记:
其实我们叫的属性是属性器,是一对Get,Set方法。既然是方法,当然不是字段了,所以是不能序列化标记或者排除的,那我们怎么去处理某些属性不需要序列化的情况列。方法也是有的,需要把属性器中的Get,Set方法写实,即该有的字段还是得定义,不能偷懒,然后在该有的字段上面标记为不需要序列化。
三:序列化的特殊用法
学过C#的时候,大家都知道了个值类型,引用类型的概念,也可能知道了ICloneable这个接口,这个克隆接口可以复制对象,如实例化个student,然后调用Clone()即可以得到该对线的浅层副本。
浅层克隆就是只把改对象的值类型和引用类型的地址复制了,但是,原来对象中的被引用类型的对象发生改变,比如:student类中有个classroom,classroom中的某个字段发生改变,这样克隆后的对线的classroom的值也是会变的。除非classroom这个类也实现ICloneable接口。
序列化克隆的好处就是不用考虑浅层复制,深层复制,直接将要克隆的对象序列化,然后反序列化得到的对象就是我们期望的结果。
处理
按照上面的说明,代码如下:
Student类
1 [Serializable]
2 public class Student
3 {
4 [field: NonSerializedAttribute()]
5 public event EventHandler Changed;
6 [NonSerialized]
7 private ExParam param;
8
9 public string ID
10 {
11 get;
12 set;
13 }
14
15 public string Name
16 {
17 get;
18 set;
19 }
20
21 public ClassRoom Room
22 {
23 get;
24 set;
25 }
26
27 public ExParam Param
28 {
29 get
30 {
31 return param;
32 }
33 set
34 {
35 param = value;
36 }
37 }
38 }
ClassRoom类
1 [Serializable]
2 public class ClassRoom
3 {
4
5 public string Name
6 {
7 get;
8 set;
9 }
10
11 public string Address
12 {
13 get;
14 set;
15 }
16 }
ExParam类
1 public class ExParam
2 {
3 public string Name
4 {
5 get;
6 set;
7 }
8 }
Util类
1 public class Util
2 {
3 public static byte[] SerializeObject(object obj)
4 {
5 if (obj == null)
6 return null;
7
8 using (MemoryStream memory = new MemoryStream())
9 {
10 BinaryFormatter formatter = new BinaryFormatter();
11 formatter.Serialize(memory, obj);
12 memory.Position = 0;
13 byte[] read = new byte[memory.Length];
14 memory.Read(read, 0, read.Length);
15 memory.Close();
16 return read;
17 }
18 }
19
20
21 public static object DeserializeObject(byte[] data)
22 {
23 object obj = null;
24 if (data == null)
25 return obj;
26
27 using (MemoryStream memory = new MemoryStream(data))
28 {
29 memory.Position = 0;
30 BinaryFormatter formatter = new BinaryFormatter();
31 obj = formatter.Deserialize(memory);
32 memory.Close();
33 return obj;
34 }
35 }
36 }
主窗体
1 private void Form1_Load(object sender, EventArgs e)
2 {
3 Student student = new Student()
4 {
5 ID = "201401",
6 Name = "攻城狮",
7 Room = new ClassRoom()
8 {
9 Name = "博客园",
10 Address = "小山村"
11 },
12 Param = new ExParam()
13 {
14 Name = "程序猿"
15 }
16 };
17
18 byte[] data = Util.SerializeObject(student);
19
20 Student student1 = Util.DeserializeObject(data) as Student;
21
22 Print(student);
23 Print(student1);
24 }
25
26 private void Print(Student student)
27 {
28 string info =string.Format("{0}{1}{2}{3}"
29 , "hashcode:" + student.GetHashCode().ToString() + " "
30 , student.ID + " " + student.Name + " "
31 , student.Room != null ? student.Room.Name + " " + student.Room.Address + " "+student.Room.GetHashCode().ToString()+" " : "room is null "
32 , student.Param != null ? student.Param.Name : "param is null"
33 );
34 listPrint.Items.Add(info);
35 }
从上述代码输出的结果我们可以看出
student是被序列化的,student1是用student的序列化的二进制反序列化出来的,两个的hashcode不一样,所以是两个对象。
标记了序列化的字段都被序列化了,没标记的序列化字段Param是空的托福答案
student中的属性Room是引用类型,标记为序列化,student和student1的Room里的值内容一样但是hashcode不一样,所以这Room也是我们期望的两个对象。
.NET序列化的一点技巧的更多相关文章
- .NET序列化的一点技巧(附Demo)
阅读目录 介绍 详细 处理 结论 Demo下载 介绍 序列化是将对象状态转换为可保持或传输的形式的过程.序列化的补集是反序列化,后者将流转换为对象.这两个过程一起保证数据易于存储和传输. .NET F ...
- dubbo序列化的一点注意
最近工作中遇见了一个小问题,在此记录一下,大致是这样的,有一父类,有一个属性traceId,主要是记录日志号,这样可以把所有日志串起来,利于排查问题,所有的pojo对象继承于此,但是其中一同事在子类p ...
- Javascript 性能优化的一点技巧
把优秀的编程方式当成一种习惯,融入到日常的编程当中.下图是今天想到的一点Javascript 性能优化的技巧,分享一下,抛砖引玉.
- Json.Net组件指定/忽略序列化字段属性技巧知识点
我们在用Json.Net序列化组件序列化类的时候,经常有这样的一个需求:指定被序列化类中的某些字段属性是要忽略的,或者是指定字段属性序列化 比如下面这个类: public class Bar { pu ...
- C语言下for循环的一点技巧总结
for循环是普遍应用与各种计算机语言的一种循环方式. 一般情况下, for循环规则:for(条件一:条件二:条件三) 条件一为满足条件,也就是条件一为1时,进入这个for循环.条件二为循环条件,也就是 ...
- SpringMVC DispatcherServlet在配置Rest url-pattern的一点技巧
SpringMVC的Controller中已经有了@RequestMapping(value = "detail.do", method = RequestMethod.GET)的 ...
- 关于反编译pyc的一点技巧
现在最流行的是用 https://github.com/rocky/python-uncompyle6 但是有些python小版本不一样,比如2.7.6的某版本,开头的magic number在这个项 ...
- java.io.Serializable 序列化接口
什么是序列化.反序列化? Serialization(序列化)是一种将对象以一连串的字节描述的过程: 反序列化deserialization是一种将这些字节重建成一个对象的过程. 序列化通俗一点说就是 ...
- 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化
序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...
随机推荐
- 53个要点提高php效率
用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说 ...
- JVM类载入过程及主动引用与被动引用
了解类载入全过程,有助于了解JVM执行过程,以及更深入了解java动态性(解热部署,动态载入),提高程序灵活性. 类载入全过程: JVM将class文件字节码文件载入到内存中.并对数据进行校验解析和初 ...
- Delphi十进制和十六进制互转
Delphi 自带函数 IntToHex 功能说明:该函数用于将“十进制”转换成“十六进制”.该函数有二个参数.第一个参数为要转换的十进制数据,第二个参数是指定使用多少位来显示十六进制数据. 参考实例 ...
- iOS--iOS7摄像头识别二维码功能
iOS–iOS7摄像头识别二维码功能 属性介绍: AVFoundation 框架基于以下几个类实现图像捕捉 ,通过这些类可以访问来自相机设备的原始数据并控制它的组件. AVCaptureDevice ...
- Programming a Spider in Java 源码帖
Programming a Spider in Java 源码帖 Listing 1: Finding the bad links (CheckLinks.java) import java.awt. ...
- xcode 6.4模拟器出现多个相同版本:OSX Yosemite 上安装xcode7 beta和xcode6.4
错误现象是:我在OSX Yosemite上同时安装了Xcode 7Beta和Xcode 6.4,然后Xcode 6.4的模拟器出现了重复版本.截图如下: 解决方法是: 删除该路径下的所有文件:~/Li ...
- Web的鼠标拖动效果
以前写过一个拖动效果的Demo,拖拽元素新位置的计算是放在拖拽元素的mousemove事件中进行的.计算效率差,而且效果不好.所以一直有想怎样才能做出jquery-ui那种顺滑的拖拽效果. 其实顺滑的 ...
- Java使用poi对Execl简单_读和写_操作
1 /** 一.简单读取Execl的步骤: * 1.通过流来读取Execl并存放到内存中: * 2.通过WorkbookFactory工作簿工厂来读取内存中存放的execl文档流并创建出一个工作簿 * ...
- RSA签名验签
import android.util.Base64; import java.security.KeyFactory; import java.security.PrivateKey; import ...
- SQL:42601
以前遇到SQL中触发器的问题, 添加一个字段后,发现以前的程序的SQL报错 看了下表定义,有这样的一行代码 CREATE TRIGGER chintai_keiyaku_audit AFTER INS ...