C#中的自动属性对wcf 序列化 null 属性是否有影响

深入理解C#序列化与反序列化的详解
字体:[ ] 类型:转载 时间:
本篇文章是对C#中序列化与反序列化进行了详细的分析介绍,需要的朋友参考下
在我们深入探讨C#序列化和反序列化之前我们先要明白什么是序列化,它又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用。其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。.NET框架提供了两种串行化的方式:1、是使用BinaryFormatter进行串行化;2、使用SoapFormatter进行串行化;3、使用XmlSerializer进行串行化。第一种方式提供了一个简单的二进制数据流以及某些附加的类型信息,而第二种将数据流格式化为XML存储;第三种其实和第二种差不多也是XML的格式存储,只不过比第二种的XML格式要简化很多(去掉了SOAP特有的额外信息)。可以使用[Serializable]属性将类标志为可序列化的。如果某个类的元素不想被序列化,1、2可以使用[NonSerialized]属性来标志,2、可以使用[XmlIgnore]来标志。下面就让我们开始深入了解C#序列化和反序列化:C#序列化和反序列化1、使用BinaryFormatter进行串行化下面是一个可串行化的类: 代码如下:using S& using System.D& using System.C& using System.W& using System.Web.S& using System.Web.UI;& using System.Web.UI.WebC& using System.Web.UI.WebControls.WebP& using System.Web.UI.HtmlC& using System.IO;& using System.Runtime.Serialization.Formatters.B& /**//// ﹤summary﹥& /// ClassToSerialize 的摘要说明& /// ﹤/summary﹥& [Serializable]& public class ClassToSerialize& {& &&& public int id = 100;& &&& public string name = "Name";& &&& [NonSerialized]& &&& public string Sex = "男";& }下面是串行化和反串行化的方法: 代码如下:public void SerializeNow()& {& &&& ClassToSerialize c = new ClassToSerialize();& &&& FileStream fileStream =&& &&& new FileStream("c:\\temp.dat", FileMode.Create);& &&& BinaryFormatter b = new BinaryFormatter();& &&& b.Serialize(fileStream, c);& &&& fileStream.Close();& }& public void DeSerializeNow()& {& &&& ClassToSerialize c = new ClassToSerialize();& &&& c.Sex = "kkkk";& &&& FileStream fileStream =& &&& new FileStream("c:\\temp.dat",&& &&& FileMode.Open, FileAccess.Read, FileShare.Read);& &&& BinaryFormatter b = new BinaryFormatter();& &&& c = b.Deserialize(fileStream) as ClassToS& &&& Response.Write(c.name);& &&& Response.Write(c.Sex);& &&& fileStream.Close();& } 调用上述两个方法可以看到串行化的结果:Sex属性因为被标志为[NonSerialized],故其值总是为null。C#序列化和反序列化2、使用SoapFormatter进行串行化和BinaryFormatter类似,我们只需要做一下简单修改即可:a.将using语句中的.Formatter.Binary改为.Formatter.Sb.将所有的BinaryFormatter替换为SoapFormatter.c.确保报存文件的扩展名为.xml经过上面简单改动,即可实现SoapFormatter的串行化,这时候产生的文件就是一个xml格式的文件。C#序列化和反序列化3、使用XmlSerializer进行串行化关于格式化器还有一个问题,假设我们需要XML,但是不想要SOAP特有的额外信息,那么我们应该怎么办呢?有两中方案:要么编写一个实现IFormatter接口的类,采用的方式类似于SoapFormatter类,但是没有你不需要的信息;要么使用库类XmlSerializer,这个类不使用Serializable属性,但是它提供了类似的功能。如果我们不想使用主流的串行化机制,而想使用XmlSeralizer进行串行化我们需要做一下修改:a.添加System.Xml.Serialization命名空间。b.Serializable和NoSerialized属性将被忽略,而是使用XmlIgnore属性,它的行为与NoSerialized类似。c.XmlSeralizer要求类有个默认的构造器,这个条件可能已经满足了。下面看C#序列化和反序列化示例:要序列化的类: 代码如下:using S& using System.D& using System.C& using System.W& using System.Web.S& using System.Web.UI;& using System.Web.UI.WebC& using System.Web.UI.WebControls.WebP& using System.Web.UI.HtmlC& using System.Xml.S& 代码如下:[Serializable]& public class Person& {& &&&& &&& public string Name& &&& {& &&&&&&& get &&&&&&& {& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&&&&& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&}& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&set &SPAN style="WHITE-SPACE: pre"&&&/SPAN&{& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&&&& name =& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&}& &&& }& &&&& public string S& &&& public int Age = 31;& &&& public Course[] C& &&& public Person()& &&& {& &&& }& &&& public Person(string Name)& &&& {& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&name = N& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&Sex = "男";& &&& }& } & 代码如下:[Serializable]& public class Course& {& &&& public string N& &&& [XmlIgnore]& &&& public string D& &&& public Course()& &&& {& &&& }& &&& public Course(string name, string description)& &&& {& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&Name =& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&Description =& &&& }& } C#序列化和反序列化方法: 代码如下:public void XMLSerialize()& {& &&& Person c = new Person("cyj");& &&& c.Courses = new Course[2];& &&& c.Courses[0] = new Course("英语", "交流工具");& &&& c.Courses[1] = new Course("数学","自然科学");& &&& XmlSerializer xs = new XmlSerializer(typeof(Person));& &&& Stream stream = new FileStream("c:\\cyj.XML",FileMode.Create,FileAccess.Write,FileShare.Read);& &&& xs.Serialize(stream,c);& &&& stream.Close();& }& public void XMLDeserialize()& {& &&& XmlSerializer xs = new XmlSerializer(typeof(Person));& &&& Stream stream = new FileStream("C:\\cyj.XML",FileMode.Open,FileAccess.Read,FileShare.Read);& &&& Person p = xs.Deserialize(stream) as P& &&& Response.Write(p.Name);& &&& Response.Write(p.Age.ToString());& &&& Response.Write(p.Courses[0].Name);& &&& Response.Write(p.Courses[0].Description);& &&& Response.Write(p.Courses[1].Name);& &&& Response.Write(p.Courses[1].Description);& &&& stream.Close();& } 这里Course类的Description属性值将始终为null,生成的xml文档中也没有该节点,如下: 代码如下:﹤?xml version="1.0"?﹥& ﹤Person xmlns:xsi=& "http://www.w3.org/2001/XMLSchema-instance"&& xmlns:xsd="http://www.w3.org/2001/XMLSchema"﹥& & ﹤Sex﹥男﹤/Sex﹥& & ﹤Age﹥31﹤/Age﹥& & ﹤Courses﹥& ﹤Course﹥& & ﹤Name﹥英语﹤/Name﹥& & ﹤Description﹥交流工具﹤/Description﹥& ﹤/Course﹥& ﹤Course﹥& & ﹤Name﹥数学﹤/Name﹥& & ﹤Description﹥自然科学﹤/Description﹥& ﹤/Course﹥& & ﹤/Courses﹥& & ﹤Name﹥cyj﹤/Name﹥& ﹤/Person﹥C#序列化和反序列化4、自定义序列化如果你希望让用户对类进行串行化,但是对数据流的组织方式不完全满意,那么可以通过在自定义类中实现接口来自定义串行化行为。这个接口只有一个方法,GetObjectData. 这个方法用于将对类对象进行串行化所需要的数据填进SerializationInfo对象。你使用的格式化器将构造SerializationInfo对象,然后在串行化时调用GetObjectData. 如果类的父类也实现了ISerializable,那么应该调用GetObjectData的父类实现。如果你实现了ISerializable,那么还必须提供一个具有特定原型的构造器,这个构造器的参数列表必须与GetObjectData相同。这个构造器应该被声明为私有的或受保护的,以防止粗心的开发人员直接使用它。示例如下:C#序列化和反序列化之实现ISerializable的类: 代码如下:using S& using System.D& using System.C& using System.W& using System.Web.S& using System.Web.UI;& using System.Web.UI.WebC& using System.Web.UI.WebControls.WebP& using System.Web.UI.HtmlC& using System.Runtime.S& using System.Runtime.Serialization.Formatters.B& /**//// ﹤summary﹥& /// Employee 的摘要说明& /// ﹤/summary﹥& [Serializable]& public class Employee:ISerializable& {& &&& public int EmpId=100;& &&& public string EmpName="刘德华";& &&& [NonSerialized]& &&& public string NoSerialString = "NoSerialString-Test";& &&& public Employee()& &&& {& &&&&&&& //& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&// TODO: 在此处添加构造函数逻辑& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&//& &&& }& &&& private Employee(SerializationInfo info, StreamingContext ctxt)& &&& {& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&EmpId = (int)info.GetValue("EmployeeId", typeof(int));& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&EmpName = (String)info.GetValue("EmployeeName",typeof(string));& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&//NoSerialString = (String)info.GetValue("EmployeeString",typeof(string));& &&& }& &&& public void GetObjectData(SerializationInfo info, StreamingContext ctxt)& &&& {& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&info.AddValue("EmployeeId", EmpId);& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&info.AddValue("EmployeeName", EmpName);& &SPAN style="WHITE-SPACE: pre"&&&/SPAN&//info.AddValue("EmployeeString", NoSerialString);& &&& }& } C#序列化和反序列化方法: 代码如下:public void OtherEmployeeClassTest()& {& &&& Employee mp = new Employee();& &&& mp.EmpId = 10;& &&& mp.EmpName = "邱枫";& &&& mp.NoSerialString = "你好呀";& &&& Stream steam = File.Open("c:\\temp3.dat", FileMode.Create);& &&& BinaryFormatter bf = new BinaryFormatter();& &&& Response.Write("Writing Employee Info:");& &&& bf.Serialize(steam,mp);& &&& steam.Close();& &&& mp =& &&& //C#序列化和反序列化之反序列化& &&& Stream steam2 = File.Open("c:\\temp3.dat", FileMode.Open);& &&& BinaryFormatter bf2 = new BinaryFormatter();& &&& Response.Write("Reading Employee Info:");& &&& Employee mp2 = (Employee)bf2.Deserialize(steam2);& &&& steam2.Close();& &&& Response.Write(mp2.EmpId);& &&& Response.Write(mp2.EmpName);& &&& Response.Write(mp2.NoSerialString);& } C#序列化和反序列化的深入探讨就是一个体验和尝试的过程,那么希望本文对你了解和学习C#序列化和反序列化有所帮助。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具当我们使用公开属性以及公开字段时,都可以顺利的被序列化,
[Serializable]
public class MyClass
public int ID;
public string A
private int _
public string Name { }
public int Age
get { return _ }
set { _age = }
Xml序列化成档案后的结果就像下图:&
bin,因为bin档案肉眼看不懂,所以用反序列化表示
但总是会有不想要存成档案的字段或属性
JSON及XML 若是不想被序列化 "属性" 及 "字段" 使用以下Attribute:
[System.Xml.Serialization.XmlIgnore][System.Web.Script.Serialization.ScriptIgnore]BinaryFormatter 若是不想被序列化 "属性" 只要在相对应的 "字段" 使用以下:[NonSerialized] 看个例子:
[Serializable]
public class MyClass
[NonSerialized]
public int ID;
public string A
[NonSerialized]
private int _
public string Name { }
[System.Xml.Serialization.XmlIgnore]
[System.Web.Script.Serialization.ScriptIgnore]
public int Age
get { return _ }
set { _age = }
Xml序列化,忽略Age属性&
JSON序列化,忽略Age属性&
BinaryFormatter序列化忽略 Age属性 及 ID 字段&
延伸阅读:
阅读(...) 评论()谈谈:.Net中的序列化和反序列化
我的图书馆
谈谈:.Net中的序列化和反序列化
序列化和反序列化相信大家都经常听到,也都会用, 然而有些人可能不知道:.net为什么要有这个东西以及.net Frameword如何为我们实现这样的机制, 在这里我也是简单谈谈我对序列化和反序列化的一些理解。
一、什么序列化和反序列化
序列化通俗地讲就是将一个对象转换成一个字节流的过程,这样就可以轻松保存在磁盘文件或数据库中。反序列化是序列化的逆过程,就是将一个字节流转换回原来的对象的过程。
然而为什么需要序列化和反序列化这样的机制呢?这个问题也就涉及到序列化和反序列化的用途了,
对于序列化的主要用途有:
将应用程序的状态保存在一个磁盘文件或数据库中,并在应用程序下次运行时恢复状态。例如, Asp.net 中利用序列化和反序列化来保存和恢复会话状态。
一组对象可以轻松复制到Windows 窗体的剪贴板中,再粘贴回同一个或者另一个应用程序。
将对象按值从一个应用程序域中发送到另一个程序域
并且如果把对象序列化成内存中的字节流,就可以利用一些其他的技术来处理数据,例如,对数据进行加密和压缩等。
二、序列化和反序列简单使用
.Net Framework 提供二种序列化方式:
二进制序列化
XML 和SOAP序列化
序列化和反序列化的简单使用:
using System.IO;
using System.Runtime.Serialization.Formatters.B
namespace Serializable
[Serializable]
public class Person
public string personN
[NonSerialized]
public string personH
private int personA
public int PersonAge
get { return personA }
set { personAge = }
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 = "<SPAN style="COLOR: #5CM";
person.PersonAge = <SPAN style="COLOR: #;
Stream stream = Serialize(person);
//为了演示,都重置
stream.Position = <SPAN style="COLOR: #;
person = null;
person = Deserialize(stream);
person.Write();
Console.Read();
private static MemoryStream Serialize(Person person)
MemoryStream stream = new MemoryStream();
// 构造二进制序列化格式器
BinaryFormatter binaryFormatter = new BinaryFormatter();
// 告诉序列化器将对象序列化到一个流中
binaryFormatter.Serialize(stream, person);
private static Person Deserialize(Stream stream)
BinaryFormatter binaryFormatter = new BinaryFormatter();
return (Person)binaryFormatter.Deserialize(stream);
主要是调用System.Runtime.Serialization.Formatters.Binary命名空间下的BinnaryFormatter类来进行序列化和反序列化,调用反序列化后的结果截图:
从中可以看出除了标记NonSerialized的其他成员都能序列化,注意这个属性只能应用于一个类型中的字段,而且会被派生类型继承。
SOAP 和XML 的序列化和反序列化和上面类似,只需要改下格式化器就可以了, 这里我就不列出来了。
三、控制序列化和反序列化
  有两种方式来实现控制序列化和反序列化:
通过OnSerializing, OnSerialized,OnDeserializing, OnDeserialized,NonSerialized和OptionalField等属性
实现System.Runtime.Serialization.ISerializable接口
第一种方式实现控制序列化和反序列化代码:
using System.IO;
using System.Runtime.S
using System.Runtime.Serialization.Formatters.B
namespace ControlSerialization
[Serializable]
public class Circle
private double //半径
[NonSerialized]
public double //面积
public Circle(double inputradiu)
area = Math.PI * radius *
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
area = Math.PI * 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(<SPAN style="COLOR: #);
MemoryStream stream =new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
// 将对象序列化到内存流中,这里可以使用System.IO.Stream抽象类中派生的任何类型的一个对象, 这里我使用了 MemoryStream类型。
formatter.Serialize(stream,c);
stream.Position = <SPAN style="COLOR: #;
c = (Circle)formatter.Deserialize(stream);
c.Write();
Console.Read();
运行结果为:
注意:如果注释掉 OnDeserialized属性的话,area字段的值就是0了,因为area字段没有被序列化到流中。
在上面需要序列化的对象中,格式化器只会序列化对象的radius字段的值。area字段中的值不会序列化,因为该字段已经应用了NonSerializedAttribute属性,然后我们用Circle c=new Circle(10)这样代码构建一个Circle对象时,在内部,area会设置一个约为314.159这样的值,这个对象序列化时,只有radius的字段的值(10)写入流中, 但当反序列化成一个Circle对象时,它的area字段的值会初始化为0,而不是约314.159的一个值。为了解决这样的问题,所以自定义一个方法应用OnDeserializedAttribute属性。此时的执行过程为:每次反序列化类型的一个实例,格式化器都会检查类型中是否定义了 一个应用了该attribute的方法,如果是,就调用该方法,调用该方法时,所有可序列化的字段都会被正确设置。除了OnDeserializedAttribute这个定制attribute,system.Runtime.Serialization命名空间还定义了OnSerializingAttribute,OnSerializedAttribute和OnDeserializingAttribute这些定制属性。
实现ISerializable接口方式控制序列化和反序列化代码:
using System.IO;
using System.Runtime.S
using System.Runtime.Serialization.Formatters.B
using System.Security.P
namespace ControlSerilization2
[Serializable]
public class MyObject : ISerializable
public int n1;
public intn2;
[NonSerialized]
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 = <SPAN style="COLOR: #;
obj.n2 = <SPAN style="COLOR: #;
obj.str = "Jeffy";
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
// 将对象序列化到内存流中,这里可以使用System.IO.Stream抽象类中派生的任何类型的一个对象, 这里我使用了 MemoryStream类型。
formatter.Serialize(stream, obj);
stream.Position = <SPAN style="COLOR: #;
obj = null;
obj = (MyObject)formatter.Deserialize(stream);
obj.Write();
Console.Read();
此时的执行过程为:当格式化器序列化对象时,会检查每个对象,如果发现一个对象的类型实现了ISerializable接口,格式化器会忽视所有定制属性,改为构造一个新的System.Runtime.Serialization.SerializationInfo对象,这个对象包含了要实际为对象序列化的值的集合。构造好并初始化好SerializationInfo对象后,格式化器调用类型的GetObjectData方法,并向它传递对SerializationInfo对象的引用,GetObjectData方法负责决定需要哪些信息来序列化对象,并将这些信息添加到SerializationInfo对象中,通过调用AddValue方法来添加需要的每个数据,添加好所有必要的序列化信息后,会返回至格式化器,然后格式化器获取已经添加到SerializationInfo对象中的所有值,并将它们都序列化到流中,当反序列化时,格式化器从流中提取一个对象时,会为新对象分配内存,最初,这个对象的所有字段都设为0或null,然后,格式化器检查类型是否实现了ISerializable接口,如果存在这个接口, 格式化器就尝试调用一个特殊构造器,它的参数和GetObjectData方法的完全一致。
四、格式化器如何序列化和反序列化
从上面的分析中可以看出,进行序列化和反序列化主要是格式化器在工作的,然而下面就是要讲讲格式化器是如何序列化一个应用了 SerializableAttribute 属性的对象。
格式化器调用FormatterServices的GetSerializableMembers方法:public static MemberInfo[] GetSerializableMembers(Type type,StreamingContext context);这个方法利用发射获取类型的public和private实现字段(标记了NonSerializedAttributee属性的字段除外)。方法返回由MemberInfo对象构成的一个数组,其中每个元素对应于一个可序列化的实例字段。
对象被序列化,System.Reflection.MemberInfo对象数组传给FormatterServices的静态方法GetObjectData: public static object[] GetObjectData(Object obj,MemberInfo[] members);& 这个方法返回一个Object数组,其中每个元素都标识了被序列化的那个对象中的一个字段的值。
格式化器将程序集标识和类型的完整名称写入流中。
格式化器然后遍历两个数组中的元素,将每个成员的名称和值写入流中。
接下来是解释格式化器如何自动反序列化一个应用了 SerializableAttribute属性的对象。
格式化器从流中读取程序集标识和完整类型名称。
格式化器调用FormatterServices的静态方法GetUninitializedObject: public static Object GetUninitializedObject(Type ttype);这个方法为一个新对象分配内存,但不为对象调用构造器。然而,对象的所有字段都被初始化为0或null.
格式化器现在构造并初始化一个MemberInfo数组,调用FormatterServices的GetSerializableMembers方法,这个方法返回序列化好、现在需要反序列化的一组字段。
格式化器根据流中包含的数据创建并初始化一个Object数组。
将对新分配的对象、MemberInfo数组以及并行Object数组的引用传给FormatterServices的静态方法PopulateObjectMembers:
&&&&&&&&& public static Object PopulateObjectMembers(Object obj,MemberInfo[] members,Object[] data);这个方法遍历数组,将每个字段初始化成对应的值。
注:格式化如何序列化和反序列对象部分摘自CLR via C#(第三版),写在这里可以让初学者进一步理解格式化器在序列化和反序列化过程中所做的工作。
写到这里这篇关于序列化和反序列的文章终于结束了, 希望对自己以后复习和园子里的朋友有帮助。
TA的推荐TA的最新馆藏
喜欢该文的人也喜欢}

我要回帖

更多关于 dubbo序列化丢失属性 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信