C#序列化与反序列化方式简单总结

时间:2024-06-14 11:35:38

序列化和反序列化

相关类:

System.SerializableAttribute特性(或称为属性),

System.Runtime.Serialization.ISerializable(自定义序列化接口)

https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.iserializable.aspx,

System.Runtime.Serialization.IserializationSurrogate(自定义序列化代理接口),

System.Runtime.Serializatin.SurrogateSelector(自定义序列化代理设置类)

1:官方备注

序列化使用

BinaryFormatter(https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx)或

SopaFormatter(https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.formatters.soap.soapformatter.aspx),使用方法类同。

System.SerializableAttribute特性:

将SerializableAttribute特性应用于一个类型可指示该类型的实例可以序化。如果正在序列化的对象图中的任何类型未应用SerializableAttribute特性,公共语言运行时则会引发SerializableException(https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.serializationexception.aspx)。

即使该类会实现ISerializable接口来控制序列化进程,仍要应用SerializableAttribute特性。

将SerializableAttribute特性应用于类型时,序列化默认情况下所有私有和公共字段。

也可以从序列化排除字段通过应用NonSerializedAttribute(https://msdn.microsoft.com/zh-cn/library/system.nonserializedattribute.aspx)特性应用于字段。如果可序列化类型的字段包含指针、句柄或其他模型针对于特定环境的数据结构,并且不能在不同的环境中以有异议的方式重建,则最好经NonSerializableAttribute特性应用于该字段。

System.Runtime.Serialization.ISerializable接口:

任何可以序列化的类都必须用SerializableAttribute进行标记。如果某个类需要控制器序列化进程,它可以实现ISerializable接口。Formatter(https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.formatter.aspx)在序列化时调用GetObjectData,并使用表示对象所需的全部数据来填充所提供的SerializationInfo(https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.serializationinfo.aspx)。Formatter使用图形中对象的类型来创建SerializationInfo。需要自己发送代理的对象可以使用SerializationInfo上的FullTypeName和AssemblyName属性来更改所传输的信息,或直接使用方法SetType,与同时设置FullTypeName和AssemblyName等效。

在类继承的情况下,可以序列化从实现ISerializable的基类中派生的类。这种情况下,派生的类应在GetObjectData的实现内调用GetObjectData的基类实现。否则,不会序列化来自基类的数据。

ISerializable接口需要带有签字(SerializationInfo,StreamingContext)的构造函数。在反序列化时,仅在格式化程序已反序列化SerializationInfo中的数据后才调用当前构造函数。一般而言,如果该类未密封,则应保护此构造函数,序列化过程会忽略此构造方法的访问修饰符,及应当使用protected或private(类被sealed修饰时)来修饰此构造方法。

无法保证对象被反序列化的顺序。例如,如果一种类型引用尚未反序列化的类型,则会引发异常。如果创建具有这种依赖关系的类型,可以通过IDeserializationCallback(https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.ideserializationcallback.aspx)接口和OnDeserialization方法来解决该问题。

序列化接口处理像处理扩展Object的类型一样,处理扩展MarshalByRefObject(https://msdn.microsoft.com/zh-cn/library/system.marshalbyrefobject.aspx)的对象类型。这些类型都可以使用SerializableAttribute来标记,并且可以将ISerializable接口实现为其他任何对象类型。它们的对象状态将被捕获并在流中持续。

当通过System.Runtime.Remotting使用这些类型时,远程处理接口会提供一个代理项,它将取代常用的序列化,而将代理序列化为MarshalByRefObject。代理项是知道如何将特定类型的对象序列化和反序列化的帮助器。代理在大多数情况下对用户不可见,其类型将是ObjRef(https://msdn.microsoft.com/zh-cn/library/system.runtime.remoting.objref.aspx)。

作为一种常规的设计模式,类很少既使用可序列化特性来标记,又扩展MarshalByRefObject。当组合这两项特性时,开发人员应仔细考虑可能的序列化和远程处理方案。MemoryStream就是一个适用的示例。当MemoryStream的基类从MarshalByRefObject扩展时,可以捕获MemoryStream的状态并随时将其还原。因此,这样做可能是有意义的:将该流的状态序列化到数据库中,并在稍后某一时间将其还原。但是,当通过远程处理来使用时,这种类型的对象将设置代理。

有关序列化MarshalByRefObject的派生类的更多信息,请参见RemottingSurrogateSelector(https://msdn.microsoft.com/zh-cn/library/system.runtime.remoting.messaging.remotingsurrogateselector.aspx)。

关于如果实现ISerializable的更多信息,请参见自定义序列化(https://msdn.microsoft.com/zh-cn/library/ty01x675.aspx)。

System.Runtime.Serialization.ISerializationSurrogate接口:

实现序列化代理选择器,此选择器允许一个对象对另一个对象执行序列化和反序列化。

System.Runtime.Serializatin.SurrogateSelector类:

序列化代理项将为用户提供一种对象,该对象可以处理不同对象的序列化要求,并且可以再必要时转换序列化数据。该类实现接口System.Runtime.Serializatin.ISurrogateSelector。

System.Runtime.Serializatin.ISurrogateSelector接口:

实现该接口的类可用于选择代理项,以使用该代理项的序列化和反序列方法对其他类进行序列化或序列化操作。

2:简单序列化

需要使用的类有SerializableAttribute特性,和BinaryFormatter,对于不需要或不应序列化的类成员需用NonSerializableAttribute特性修饰。

代码如下:

[Serializable]

public class MyItemType{

//其他成员…

[NonSerializable]

public string IgnorField{…}

}

//序列化过程

string fileName = “[文件名]”;

MyItemType t = new MyItemType();

FileStream fs = new FileStream(fileName,FileMode.Create);

IFromatter formatter = new BinaryFormatter();

formatter.Serialize(fs, t);

fs.Close();

//反序列化过程

string fileName =  “[文件名]”;

MyItemType result = null;

FileStream fs = new FileStream(fileName, FileMode.Open);

IFormatter formatter = new BinaryFormatter();

result = formatter.Deserialize(fs);

fs.Close();

3:使用ISerializable接口实现自定义序列化

继承ISerializable接口需实现方法GetObjectData,并添加一个具有签名SerializationInfo info和StreamingContext context的构造方法以供反序列化使用,须注意的是此构造方法的访问修饰符在反序列化过程中将被忽略,因此为防止此构造方法被错误的调用应对其使用较严格的访问修饰符比如protected或private。

实现此接口的类也应当使用SerializableAttribute修饰。

代码实例:

[Serializable]

public class MyItemType:Isereializable

{

//字段….

#region 自定义序列化

private MyItemType(SerializationInfo info, StreamingContext context)

{

ThisObjectStringField = info.GetValue(“keyName”, typeof(string));

ThisObjectIntField = info.GetInt32(“keyName2”);

}

public override void GetObjectData(SerializationInfo info, StreamingContext context)

{

info.AddValue(“keyName”, ThisObjectStringField, typeof(string));

//info.AddInt32(“keyName”, ThisObjectIntField);//此行错误,info没有强类型的值添加方法

}

#endregion

}

//使用方法同于简单序列化代码实例中的使用方法

4:使用IserializationSurrogate接口实现的序列化代理项

使用IserializationSurrogate实现类可对另一个类进行序列化和反序列化。

此序列化方式使用到的类或接口还包括对代理项选择的SurrogateSelector类,Iformatter实现类(此处使用BinaryFormatter)

示例代码:

//自定义序列化代理

public class Surrogate : ISerializationSurrogate

{

public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)

{

if (obj is MyItemType)

{

MyItemType temp = (MyItemType)obj;

info.AddValue("props", temp, typeof(string));

}

}

public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)

{

if (obj is MyItemType)

{

MyItemType temp = (MyItemType)obj;

temp.MyProperty = (string)info.GetValue("props", typeof(string));

Console.WriteLine("SetObjectData");

return temp;

}

return null;

}

//使用方法

Surrogate surrogate = new Surrogate();

SurrogateSelector selector = new SurrogateSelector();

selector.AddSurrogate(typeof(MyItemType), new StreamingContext(StreamingContextStates.All), surrogate);

formatter.SurrogateSelector = selector;

FileStream fs = new FileStream(fileName, FileMode.Open);

formatter.Deserialize(fs);

fs.Close();

//总结时间:2015-03-17

//修改时间:2015-03-23