导航

C#对象序列化的基本使用

Posted on 2006-03-28 00:54  老光  阅读(10084)  评论(0编辑  收藏  举报

        (好些次没有帖上,是不是重复操作了?  ) 
        i-single

        今天在写程序的时候,想要保存一些对象。最初设计时的想法是才用xml来保存。
实际编程过程中发现这还是挺繁琐的,那么多的字段和属性,还有各种组合的类。如果用xml来保存,嵌套多,嫌麻烦!
        最重要的是,我觉得使用XML来保存东西的话,那程序就被写死了,在保存/读取的时候,必须依据指定的元素的名或者属性名什么的来操作。如果使用序列化,那所有的一切交给Serialzer来做就搞定了。我们只需要写很少的代码就可以完成这个工作。
         然后考虑使用xml序列化来保存,但是这XmlSerialzer只能保存公共字段,感觉有些不够,就用二进制序列化了。对于某个需要进行序列化工作的类,在不继承自接口ISerializable的情况下,通过增加[Serializable]属性可以允许该类可以被序列化,如:
[Serializable]
public class Car
{
         private ArrayList _wheels=new ArrayList();
         private ArrayList _Lights=new ArrayList();
         public ArrayList Wheels
         {
              get{
                   return _wheels;
              }
              set{
                   _wheels=value;
              }
         }
         public ArrayList Lights
         {
              get{
                   return _Lights;
              }
              set{
                   _Lights=value;
              }
         }
         public Car
         {
              Wheel LeftWheel=new Wheel();
              Wheel RightWheel=new Wheel();
              _wheels.Add(LeftWheel);
              _wheels.Add(RightWheel);
  
              Light LeftLight=new Light();
              Light RightLight=new Light();
              _Lights.Add(LeftLight);
              _Lights.Add(RightLight);
         }
}
[Serialzable]
public class Wheel
{
     public float Radius=0.5f;
}
[Serailzable]
public class Light
{
     public float Price=200f;
}

序列化操作:
Car myCar=new Car();
FileStream fs=null;
try
{
     FileStream fs=new FileStream(@"..\..\Test.dat",FileMode.Create);
     BinaryFormatter bf=new BinaryFormatter();
     bf.Serialize(fs,myCar);
}
catch(Exception e)
{
     Messagebox.Show(e.Message);
}
finally
{
     if(fs!=null)
          fs.Close();
}

ArrayList是支持序列化的,通过以上操作,myCar实例的数据都被保存到了Test.dat中。
如果需要加载,则只需要反序列化:
   Car myCar=(Car)bf.Deserialize(fs);
  
对于多重继承情况,使用序列化还是很方便的,尽管看起来比较傻。
子类的序列化操作在父类里完成,由于不可能给this赋值,所以再在子类里操作父类里没有的字段。

如Car的父类,Vehicle
public abstract class Vehicle
{
     private float _Weight;
     private float _Height;
     private float _Length;
     public float Weight
     {
          get{return _Weight;}
          set{_Weight=value;}
     }
     public float Height
     {
          get{return _Height;}
          set{_Height=value;}
     }
     public float Length
     {
          get{retrun _Length;}
          set{_Length=value;}
     }
     //在这里反序列化
     public virtual Vehicle LoadFromFile(string filename)
     {
      //反序列化后给属性赋值
      obj=(Vehicle)bf.Deserialze(fs);
      _Weight=obj.Weight;
      _Length=obj.Length;
      _Height=obj.Height;
  
      return (Vehicle)obj;
     }
}
在子类Car里
 public override Vehicle LoadFromFile(string filename)
 {
      //如果可以this=(Car)base.LoadFromFile(filename);那就好了,可以省很多。
      Car car=(Car)base.LoadFromFile(filename);
      _Wheels=car.Wheels;
      _Lights=car.Lights;
      return null;
 }
子类Track
 public override Vehicle LoadFromFile(string filename)
 {
      Track track=(Track)base.LoadFromFile(filename);
      _Capacity=track.Capacity;
 }
  
有了这些,在构造函数中,就可以直接从文件中加载了。
public Car()
{
}

public Car(string filename)
{
     LoadFromFile(filename);
}

 
对于某些不支持序列化操作的对象或者结构,MSDN中说Serialzer会自动辨别,只要无法序列化,会自动标记成
[NonSerialzable],通过实际操作,发现还是需要手工标记。如:
[NonSerialzable]
private Microsoft.DirectX.Direct3D.Device pDevice;

如果对象里的不可序列化字段占据了绝大部分,那也就没有什么必要进行序列化了。