.Net中对象的序列化

将一个类标记为可序列化

[Serializable]
public   class  MyObject  {
  
public int n1 = 0;
  
public int n2 = 0;
  
public String str = null;
}

 

将该类序列化为二进制文件

MyObject obj  =   new  MyObject();
obj.n1 
=   1 ;
obj.n2 
=   24 ;
obj.str 
=   " 一些字符串 " ;
IFormatter formatter 
=   new  BinaryFormatter();
Stream stream 
=   new  FileStream( " MyFile.bin " , FileMode.Create, 
FileAccess.Write, FileShare.None);
formatter.Serialize(stream, obj);
stream.Close();

 

将二进制文件反序列话为该类的实例对象

IFormatter formatter  =   new  BinaryFormatter();
Stream stream 
=   new  FileStream( " MyFile.bin " , FileMode.Open, 
FileAccess.Read, FileShare.Read);
MyObject obj 
=  (MyObject) formatter.Deserialize(fromStream);
stream.Close();

//  下面是证明
Console.WriteLine( " n1: {0} " , obj.n1);
Console.WriteLine(
" n2: {0} " , obj.n2);
Console.WriteLine(
" str: {0} " , obj.str);

 

选择性序列化

 

[Serializable]
public   class  MyObject 
{
  
public int n1;
  [NonSerialized] 
public int n2;//不需要序列化的变量
  public String str;
}

 

自定义序列化

    可以通过在对象上实现 ISerializable 接口来自定义序列化过程。这一功能在反序列化后成员变量的值失效时尤其有用,但是需要为变量提供值以重建对象的完整状态。要实现 ISerializable,需要实现 GetObjectData 方法以及一个特殊的构造函数,在反序列化对象时要用到此构造函数。

 

[Serializable]
public   class  MyObject : ISerializable 
{
  
public int n1;
  
public int n2;
  
public String str;

  
public MyObject()
  
{
  }


  
protected MyObject(SerializationInfo info, StreamingContext context)
  
{
    n1 
= info.GetInt32("i");
    n2 
= info.GetInt32("j");
    str 
= info.GetString("k");
  }


  
public virtual void GetObjectData(SerializationInfo info, 
StreamingContext context)
  
{
    info.AddValue(
"i", n1);
    info.AddValue(
"j", n2);
    info.AddValue(
"k", str);
  }

}

 

如果从实现了 ISerializable 的类派生出一个新的类,则只要新的类中含有任何需要序列化的变量,就必须同时实现构造函数以及 GetObjectData 方法。切记要在反序列化构造函数中调用基类,否则,将永远不会调用基类上的构造函数,并且在反序列化后也无法构建完整的对象。

 

[Serializable]
public   class  ObjectTwo : MyObject
{
  
public int num;

  
public ObjectTwo() : base()
  
{
  }


  
protected ObjectTwo(SerializationInfo si, StreamingContext context) : 
base(si,context)
  
{
    num 
= si.GetInt32("num");
  }


  
public override void GetObjectData(SerializationInfo si, 
StreamingContext context)
  
{
    
base.GetObjectData(si,context);
    si.AddValue(
"num", num);
  }

}

 

序列化过程的步骤

在格式化程序上调用 Serialize 方法时,对象序列化按照以下规则进行:

    • 检查格式化程序是否有代理选取器。如果有,检查代理选取器是否处理指定类型的对象。如果选取器处理此对象类型,将在代理选取器上调用 ISerializable.GetObjectData
    • 如果没有代理选取器或有却不处理此类型,将检查是否使用 Serializable 属性对对象进行标记。如果未标记,将会引发 SerializationException
    • 如果对象已被正确标记,将检查对象是否实现了 ISerializable。如果已实现,将在对象上调用 GetObjectData
    • 如果对象未实现 Serializable,将使用默认的序列化策略,对所有未标记为 NonSerialized 的字段都进行序列化。

    注意:

    1、上面所使用的 BinaryFormatter 效率很高,能生成非常紧凑的字节流。所有使用此格式化程序序列化的对象也可使用它进行反序列化,对于序列化将在 .NET 平台上进行反序列化的对象,此格式化程序无疑是一个理想工具。需要注意的是,对对象进行反序列化时并不调用构造函数。对反序列化添加这项约束,是出于性能方面的考虑。但是,这违反了对象编写者通常采用的一些运行时约定,因此,开发人员在将对象标记为可序列化时,应确保考虑了这一特殊约定。

    2、无法继承 Serializable 属性。如果从 MyObject 派生出一个新的类,则这个新的类也必须使用该属性进行标记,否则将无法序列化。

     

序列化规则

由于类编译后便无法序列化,所以在设计新类时应考虑序列化。需要考虑的问题有:是否必须跨应用程序域来发送此类?是否要远程使用此类?用户将如何使用此类?也许他们会从我的类中派生出一个需要序列化的新类。只要有这种可能性,就应将类标记为可序列化。除下列情况以外,最好将所有类都标记为可序列化:

    • 所有的类都永远也不会跨越应用程序域。如果某个类不要求序列化但需要跨越应用程序域,请从 MarshalByRefObject 派生此类。
    • 类存储仅适用于其当前实例的特殊指针。例如,如果某个类包含非受控的内存或文件句柄,请确保将这些字段标记为 NonSerialized 或根本不序列化此类。
    • 某些数据成员包含敏感信息。在这种情况下,建议实现 ISerializable 并仅序列化所要求的字段。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值