web 请求服务器,是不能传递跟客户端那种{传递任意类型的数据【类】等},只能传递字符串、或字节流等,反正传递过去不能 .XXX成员这样方式的,序列化到服务器端,反序列化,服务器需要对应的类型的。
序列化:将对象的状态信息及类型信息,转换为一种易于传输或存储形式(流,即字节序列)的过程
反序列化:与序列化相反,将流转换为对象的过程。
常用的有二进制序列化、XML序列化及JSON序列化三种序列化方式。现在一般都是json格式传输了。比一般格式更加轻量化了,更易于传输。效率更高
序列化是指将对象实例的状态存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字
节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本
NET自身提供了对二进制序列化与XML序列化的支持。我们可以借助第三方库,如Newtonsoft.Json【是个dll{动态链接库}】,来实现JSON序列化

按值封送
对象仅在创建对象的应用程序域中有效。除非对象是从 MarshalByRefObject 派生得到或标记为 Serializable,否则,任何将对象作为参数传递或
将其作为结果返回的尝试都将失败。如果对象标记为 Serializable,则该对象将被自动序列化,并从一个应用程序域传输至另一个应用程序域,然后
进行反序列化,从而在第二个应用程序域中产生出该对象的一个精确副本。此过程通常称为按值封送。
如果对象是从 MarshalByRefObject 派生得到,则从一个应用程序域传递至另一个应用程序域的是对象引用,而不是对象本身。也可以将从
MarshalByRefObject 派生得到的对象标记为 Serializable。远程使用此对象时,负责进行序列化并已预先配置为 SurrogateSelector 的格式化程
序将控制序列化过程,并用一个代理替换所有从 MarshalByRefObject 派生得到的对象。如果没有预先配置为 SurrogateSelector,序列化体系结
构将遵从下面的标准序列化规则
二进制序列化会将对象的所有属性(即使访问修饰符是private)转换到流中,XML/JSON则只转换访问修饰符为public的属性。在反序列化时,二进制形式不会调用构造函数,可以借助二进制序列化来实现深拷贝。
XML/JSON序列化不受编程语言限制,C#使用XML/JSON序列化后的数据JAVA可以很容易的按照XML或JSON的格式反序列化得到所需数据。相对而言,二进制序列化则受到编程语言的限制、
[Serializable]
public class Person
{
public Person()
{
Console.WriteLine("ctor");
}
public Person(int gender)
{
_gender = gender;
Console.WriteLine("ctor with parameter");
}
private static int TAG = 20;
private int _gender;
public string Name { set; get; }
public int Age { set; get; }
}
// 创建对象 此处使用了初始化器
var p = new Person(10)
{
Name = "xfh",
Age = 26
};
// Json序列化,只会序列化public属性
var pStr = JsonConvert.SerializeObject(p);
Console.WriteLine(System.Text.Encoding.Default.GetByteCount(pStr));
var newP2 = JsonConvert.DeserializeObject<Person>(pStr);
// **二进制序列化,**序列化所有属性及字段(即便是访问级别是private)
var binaryFormatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
binaryFormatter.Serialize(stream, p);
Console.WriteLine(stream.Length);
stream.Position = 0;
// 反序列化不会调用构造函数
var newP = (Person)binaryFormatter.Deserialize(stream);
}
// xml序列化,目标类型必须具有无参构造函数,只会序列化public属性
var xmlFormatter = new XmlSerializer(typeof(Person));
using (var stream = new MemoryStream())
using (var fs = new FileStream(@“C:\Users\xfh\Desktop\stream.xml”, FileMode.OpenOrCreate))
using (var sr = new StreamReader(stream))
using (var sw = new StreamWriter(fs))
{
// 序列化
xmlFormatter.Serialize(stream, p);
stream.Position = 0;
// 写入XML文件中
while (sr.EndOfStream == false)
{
var content = sr.ReadLine();
sw.WriteLine(content);
}
stream.Position = 0;
// 反序列化
var newP3 = (Person)xmlFormatter.Deserialize(stream);
}
流类型[memorystream、filestream、networkStream、stream等]可以方便地操作各种字节流,但是如何把现有的实例对象转换为方便传输的字节流,就需要使用序列化技术。对象实例的序列化,是指将实例对象转换为可方便存储、传输和交互的流。在.NET中,通过Serializable特性提供了序列化对象实例的机制,当一个类型被申明为Serializable后,它就能被诸如BinaryFormatter等实现了IFormatter接口的类型进行序列化和反序列化。我们可以为某些成员添加NonSerialized特性,不希望被序列化的成员。
class Program
{
static void Main(string[] args)
{
Person obj = new Person(26, "Edison Chou");
Console.WriteLine("初始状态:");
Console.WriteLine(obj);
// 序列化对象
byte[] data = Serialize(obj);
// 反序列化对象
Person newObj = DeSerialize(data);
Console.WriteLine("经过序列化和反序列化后:");
Console.WriteLine(newObj);
Console.ReadKey();
}
// 序列化对象
static byte[] Serialize(Person p)
{
// 使用二进制序列化
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
formatter.Serialize(ms, p);
return ms.ToArray();
}
}
// 反序列化对象
static Person DeSerialize(byte[] data)
{
// 使用二进制反序列化
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
Person p = formatter.Deserialize(ms) as Person;
return p;
}
}
}

.NET中提供了三种对象序列格式化类型:BinaryFormatter、SoapFormatter和XmlSerializer。
(1)BinaryFormatter
顾名思义,BinaryFormatter可用于将可序列化的对象序列化成二进制的字节流,在前面Serializable特性的代码示例中已经展示过,这里不再重复展示。
(2)SoapFormatter
SoapFormatter致力于将可序列化的类型序列化成符合SOAP规范的XML文档以供使用。在.NET中,要使用SoapFormatter需要先添加对于SoapFormatter的引用:
using System.Runtime.Serialization.Formatters.Soap;
Tips:SOAP是一种位于应用层的网络协议,它基于XML,并且是Web Service的基本协议。

[Serializable]
public class Person
{
…
public Person()
{
}
…
}
② XmlSerializer只能序列化公共成员变量;
因此,Person类中的私有成员_number便不能被XmlSerializer进行序列化
[Serializable]
public class Person
{
// 私有成员无法被XmlSerializer序列化
private int _number;
}
****综合演示SoapFormatter和XmlSerializer的使用方法:
①重新改写Person类
[Serializable]
public class Person
{
// 私有成员无法被XmlSerializer序列化
private int _number;
// 使用NonSerialized特性标记此成员不可被BinaryFormatter和SoapFormatter序列化
[NonSerialized]
public string _name;
// 使用XmlIgnore特性标记此成员不可悲XmlSerializer序列化
[XmlIgnore]
public string _univeristy;
public Person()
{
}
public Person(int i, string s, string u)
{
this._number = i;
this._name = s;
this._univeristy = u;
}
public override string ToString()
{
string result = string.Format("学号是:{0},姓名是:{1},大学是:{2}", _number, _name, _univeristy);
return result;
}
}
②新增SoapFormatter和XmlSerializer的序列化和反序列化方法
#region 01.SoapFormatter
// 序列化对象-SoapFormatter
static byte[] SoapFormatterSerialize(Person p)
{
// 使用Soap协议序列化
IFormatter formatter = new SoapFormatter();
using (MemoryStream ms = new MemoryStream())
{
formatter.Serialize(ms, p);
return ms.ToArray();
}
}
// 反序列化对象-SoapFormatter
static Person SoapFormatterDeSerialize(byte[] data)
{
// 使用Soap协议反序列化
IFormatter formatter = new SoapFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
Person p = formatter.Deserialize(ms) as Person;
return p;
}
}
#endregion
#region 02.XmlSerializer
// 序列化对象-XmlSerializer
static byte[] XmlSerializerSerialize(Person p)
{
// 使用XML规范序列化
XmlSerializer serializer = new XmlSerializer(typeof(Person));
using (MemoryStream ms = new MemoryStream())
{
serializer.Serialize(ms, p);
return ms.ToArray();
}
}
// 反序列化对象-XmlSerializer
static Person XmlSerializerDeSerialize(byte[] data)
{
// 使用XML规范反序列化
XmlSerializer serializer = new XmlSerializer(typeof(Person));
using (MemoryStream ms = new MemoryStream(data))
{
Person p = serializer.Deserialize(ms) as Person;
return p;
}
}
#endregion

对于某些类型,序列化和反序列化往往有一些特殊的操作或逻辑检查需求,这时就需要我们能够主动地控制序列化和反序列化的过程。.NET中提供的Serializable特性帮助我们非常快捷地申明了一个可序列化的类型(因此也就缺乏了灵活性),但很多时候由于业务逻辑的要求,我们需要主动地控制序列化和反序列化的过程。因此,.NET提供了ISerializable接口来满足自定义序列化需求。
下面的代码展示了自定义序列化和反序列化的类型模板:
[Serializable]
public class MyObject : ISerializable
{
protected MyObject(SerializationInfo info, StreamingContext context)
{
// 在此构造方法中实现反序列化
}
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
// 在此方法中实现序列化
}
}
如上代码所示,GetObjectData和特殊构造方法都接收两个参数:SerializationInfo 类型参数的作用类似于一个哈希表,通过key/value对来存储整个对象的内容,而StreamingContext 类型参数则包含了流的当前状态,我们可以根据此参数来判断是否需要序列化和反序列化类型独享。
如果基类实现了ISerializable接口,则派生类需要针对自己的成员实现反序列化构造方法,并且重写基类中的GetObjectData方法。
下面通过一个具体的代码示例,来了解如何在.NET程序中自定义序列化和反序列化的过程:
①首先我们需要一个需要被序列化和反序列化的类型,该类型有可能被其他类型继承
[Serializable]
public class MyObject : ISerializable
{
private int _number;
[NonSerialized]
private string _name;
public MyObject(int num, string name)
{
this._number = num;
this._name = name;
}
public override string ToString()
{
return string.Format("整数是:{0}\r\n字符串是:{1}", _number, _name);
}
// 实现自定义的序列化
protected MyObject(SerializationInfo info, StreamingContext context)
{
// 从SerializationInfo对象(类似于一个HashTable)中读取内容
this._number = info.GetInt32("MyObjectInt");
this._name = info.GetString("MyObjectString");
}
// 实现自定义的反序列化
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// 将成员对象写入SerializationInfo对象中
info.AddValue("MyObjectInt", this._number);
info.AddValue("MyObjectString", this._name);
}
}
②随后编写一个继承自MyObject的子类,并添加一个私有的成员变量。需要注意的是:子类必须负责序列化和反序列化自己添加的成员变量。
[Serializable]
public class MyObjectSon : MyObject
{
// 自己添加的成员
private string _sonName;
public MyObjectSon(int num, string name)
: base(num, name)
{
this._sonName = name;
}
public override string ToString()
{
return string.Format("{0}\r\n之类字符串是:{1}", base.ToString(), this._sonName);
}
// 实现自定义反序列化,只负责子类添加的成员
protected MyObjectSon(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this._sonName = info.GetString("MyObjectSonString");
}
// 实现自定义序列化,只负责子类添加的成员
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("MyObjectSonString", this._sonName);
}
}
③最后编写Main方法,测试自定义的序列化和反序列化
class Program
{
static void Main(string[] args)
{
MyObjectSon obj = new MyObjectSon(10086, “Edison Chou”);
Console.WriteLine(“初始对象为:”);
Console.WriteLine(obj.ToString());
// 序列化
byte[] data = Serialize(obj);
Console.WriteLine(“经过序列化与反序列化之后:”);
Console.WriteLine(DeSerialize(data));
Console.ReadKey();
}
// 序列化对象-BinaryFormatter
static byte[] Serialize(MyObject p)
{
// 使用二进制序列化
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
formatter.Serialize(ms, p);
return ms.ToArray();
}
}
// 反序列化对象-BinaryFormatter
static MyObject DeSerialize(byte[] data)
{
// 使用二进制反序列化
IFormatter formatter = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
MyObject p = formatter.Deserialize(ms) as MyObject;
return p;
}
}
}
