• 目标:要序列化如下的泛型对象为byte[],并可以反序列化 List synerroList; 主要类定义如下:  public interface ISyntaxErro  {  ISwitch_DEV VerifySwitch { get;set;}  string Expressionstr { get;set;}  ...

    目标:要序列化如下的泛型对象为byte[],并可以反序列化

    List<ISyntaxErro> synerroList;

    主要类定义如下:
        public interface ISyntaxErro
        {
            ISwitch_DEV VerifySwitch { get;set;}
            string Expressionstr { get;set;}
            SYNTAXERROTYPE SyntaxErroType { get;set;}
            string GetErroInfo();
        }

        [Serializable]
        internal class SyntaxErro : ISyntaxErro
        {
            ISwitch_DEV m_VerifySwitch;
            string m_Expressionstr;


            public SyntaxErro(ISwitch_DEV _VerifySwitch, string _Expressionstr)
            {
                m_VerifySwitch = _VerifySwitch;
                m_Expressionstr = _Expressionstr;
            }
            public ISwitch_DEV VerifySwitch { get { return m_VerifySwitch; } set { m_VerifySwitch = value; } }
            public string Expressionstr { get { return m_Expressionstr; } set { m_Expressionstr = value; } }
            public string GetErroInfo()
            {
            }
        }

        public interface ISubstation_DEV
        {
            int ID { get;}
            string Name { get;}
        }
        public interface ISwitch_DEV
        {
            int ID { get;}
            string Name { get;}
            string ShortName { get;}
            ISubstation_DEV Station { get;}
            IConditionGroup HConditionGroups { get;set;}
            IConditionGroup LConditionGroups { get;set;}
            IConditionGroup HConditionGroups_our { get;set;}
            IConditionGroup LConditionGroups_our { get;set;}
        }

        [Serializable]
        internal class Substation_DEV : ISubstation_DEV
        {
            int m_id;
            string m_name;
            public Substation_DEV(int id, string name)
            {
                m_id = id;
                m_name = name;
            }
            public int ID { get { return m_id; } }
            public string Name { get { return m_name; } }
        }
        [Serializable]
        internal abstract class Switch_DEV : ISwitch_DEV
        {
            int m_id;
            string m_name;
            string m_shortName;
            ISubstation_DEV m_station;
            [NonSerialized]
            IConditionGroup m_HConditionGroups;
            [NonSerialized]
            IConditionGroup m_LConditionGroups;
            [NonSerialized]
            IConditionGroup m_HConditionGroups_our;
            [NonSerialized]
            IConditionGroup m_LConditionGroups_our;
            public Switch_DEV(int id, string name, string shortName, ISubstation_DEV station)
            {
                m_id = id;
                m_name = name;
                m_shortName = shortName;
                m_station = station;
            }
            public int ID { get { return m_id; } }
            public string Name { get { return m_name; } }
            public string ShortName { get { return m_shortName; } }
            public ISubstation_DEV Station { get { return m_station; } }


            public IConditionGroup HConditionGroups { get { return m_HConditionGroups; } set { m_HConditionGroups = value; } }
            public IConditionGroup LConditionGroups { get { return m_LConditionGroups; } set { m_LConditionGroups = value; } }
            public IConditionGroup HConditionGroups_our { get { return m_HConditionGroups_our; } set { m_HConditionGroups_our = value; } }
            public IConditionGroup LConditionGroups_our { get { return m_LConditionGroups_our; } set { m_LConditionGroups_our = value; } }

        }


    序列化及反序列化方法(从其他地方借鉴并进行了简单修改):

            public static byte[] SerializeToBuffer<T>(T obj)
            {
                try
                {
                    IFormatter formatter = new BinaryFormatter();
                    MemoryStream stream = new MemoryStream();
                    formatter.Serialize(stream, obj);
                    stream.Position = 0;
                    byte[] buffer = new byte[stream.Length];
                    stream.Read(buffer, 0, buffer.Length);
                    stream.Flush();
                    stream.Close();
                    return buffer;
                }
                catch (Exception ex)
                {
                    throw new Exception("序列化失败,原因:" + ex.Message);
                }
            }

            public static T DesrializeFromBuffer<T>(T obj, byte[] buffer)
            {
                try
                {
                    obj = default(T);
                    IFormatter formatter = new BinaryFormatter();
                    MemoryStream stream = new MemoryStream(buffer);
                    obj = (T)formatter.Deserialize(stream);
                    stream.Flush();
                    stream.Close();
                }
                catch (Exception ex)
                {
                    throw new Exception("反序列化失败,原因:" + ex.Message);
                }
                return obj;
            }

    经过使用,以上方法可行,特此记录


    展开全文
  • .net framework的类库中提供了三个可以用于序列化反序列化的类,分别为BinaryFormatter、SoapFormatter和XmlSerializer。 BinaryFormatter的命名空间为System.Runtime.Serialization.Formatters.Binary,位于程序...

    (一)使用总体说明

    .net framework的类库中提供了三个可以用于序列化和反序列化的类,分别为BinaryFormatter、SoapFormatter和XmlSerializer。

    BinaryFormatter的命名空间为System.Runtime.Serialization.Formatters.Binary,位于程序集mscorlib.dll中。

    SoapFormatter的命名空间为System.Runtime.Serialization.Formatters.Soap,位于程序集System.Runtime.Serialization.Formatters.Soap.dll中。必须引用System.Runtime.Serialization.Formatters.Soap.dll。

    XmlSerializer的命名空间为System.Xml.Serialization,位于程序集System.Xml.dll中。

    ****非常重要****。需要说明的是,反序列化的过程(从文件-->对象的过程),不是new出来新对象,然后对其进行赋值的。反序列化的时候,不是依据类代码对各个成员进行初步赋值,然后执行构造函数的过程。在反序列化的时候,既不会为成员初赋值,也不会执行构造函数,而是直接对没有标注为[NonSerialized]的字段赋给其保存在文件中的值,而对于标注为[NonSerialized]的字段,其结果仅仅是default(FiledType),此处的FieldType是指字段的类型(注:可以利用OnSerialized方法来事后修改字段的值)。例如:

    [Serializable]

    public class MyClass

    {

            public MyClass()

            {

                //在反序列化的时候,不会执行构造函数

            }

            private int x=10;   //在反序列化的时候,不是将10赋值给x。而是从数据文件中读取相应的值,直接赋值给x。

           [NonSerializable]

           private int y=15;   //在反序列化的时候,不会将15赋值给y。由于y标注了[NonSerializable],因此,反序列化完成的时候,y的值是default(int),也就是0。

            private List<string> Strs=new List<string>();  //在反序列化的时候,不会new一个将List<string>并且赋值给Strs。而是从数据文件中读取相应的值,直接赋值给Strs。

           [NonSerializable]

            private List<string> AnotherStrs=new List<string>();  //在反序列化的时候,不会new一个List<string>并且将其赋值给AnotherStrs。由于AnotherStrs标注了[NonSerializable],因此,反序列化完成的时候,AnotherStrs的值是default(List<string>),也就是null。

    }

     

    (二)对三个序列化类的说明

    (1)BinaryFormatter

     可以对单个对象或集合对象(如List<T>、ObservableCollection<T>)进行序列化。需要指出的是,需要对被序列化的对象添加[Serializable]特性。典型的代码如下:

         private void BinarySerialize()
            {
                BinaryFormatter binFormat = new BinaryFormatter();
                string fileName = ...;          
                using (Stream fStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                {
                    //RecentProjectInfos是ObservableCollection<ProjectInfo>类型的属性
                     binFormat.Serialize(fStream, RecentProjectInfos);    
                }
            }
           
            private void BinaryDeserialize()
            {
                BinaryFormatter binFormat = new BinaryFormatter();
                string fileName = ...;   
                using (Stream fStream = File.OpenRead(fileName))
                {
         ObservableCollection<ProjectInfo> pis = binFormat.Deserialize(fStream) as ObservableCollection<ProjectInfo>;
                    //RecentProjectInfos是ObservableCollection<ProjectInfo>类型的属性
                    this.RecentProjectInfos=pis;
                }
            }

    (2)SoapFormatter

    可以对单个对象进行序列化。但是,很大的缺陷在于,不能直接对泛型集合数据(如List<T>、ObservableCollection<T>)进行序列化(注:无论是根对象就是泛型集合,还是某个对象下的字段或属性是泛型集合,都不能序列化),而要使用BinaryFormatter或XmlSerializer进行序列化。由于无法对泛型集合对象进行序列化,因此使用面比较窄,个人不建议使用SoapFormatter。

    (3)XmlSerializer

    无论对于单个对象还是集合对象(如List<T>、ObservableCollection<T>),都可以使用XmlSerializer进行序列化。需要指出的是,不需要对被序列化的对象添加[Serializable]特性注解。但是,使用XmlSeriabizable的时候,被序列化的对象应该具有无参数构造函数。典型的代码如下:

            private void XmlSerialize()
            {
                XmlSerializer binFormat = new XmlSerializer(typeof(ObservableCollection<ProjectInfo>)); //把对象类型作为参数
                string fileName = ...;          
                using (Stream fStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                {
                    //RecentProjectInfos是ObservableCollection<ProjectInfo>类型的属性
                     binFormat.Serialize(fStream, RecentProjectInfos);    
                }
            }
           
            private void XmlDeserialize()
            {
                XmlSerializer binFormat = new XmlSerializer(typeof(ObservableCollection<ProjectInfo>));//把对象类型作为参数
                string fileName = ...;   
                using (Stream fStream = File.OpenRead(fileName))
                {
         ObservableCollection<ProjectInfo> pis = binFormat.Deserialize(fStream) as ObservableCollection<ProjectInfo>;
                    //RecentProjectInfos是ObservableCollection<ProjectInfo>类型的属性
                    this.RecentProjectInfos=pis;
                }

            }

    (三)其它重要事项

    (1)对于BinaryFormatter,对象中的事件字段、ICommand字段都不能序列化。对于ICommand字段,需要加上[Nonserialized]特性;对于事件对象event,不能用[Nonserialized],而应该使用[field:Nonserialized]特性。

    (2)BinaryFormatter能够对所有字段(私有、保护、公有)进行序列化和反序列化,而XmlSerializer只能对共有字段进行序列化。

    (3)使用BinaryFormatter时,当调用Deserialize时,系统从文件读取数据构件.net对象,然而,在构件.net对象的过程中,不会调用对象的任何一个构造函数。而有时常常在构造函数中配置字段、关注事件、初始化ICommand对象等动作。

    首先,对于配置字段,是不存在问题的,因为所有字段都会被原封不动的复制过来,也就是相当于新生成的对象的各字段都是相当于clone过来的,不需要再次在构造函数中去配置了。

    其次,对于ICommand对象的初始化,不要放在构造函数中进行,而要直接放在ICommand属性的get方法中初始化,这样就不会出现问题。

    最后,对于关注事件,则由于缺乏对构造函数的调用,就无法关注事件了,因此,需要为类定制序列化的特定方法。.net平台提供了多个生命周期的事件处理方法,用特性[OnDeserializing]、[OnDeserialized]、[OnSerializing]、[OnSerialized]来配置特定的方法。

    [ISerializable]

    public class ProjectInfo

    {

        public ProjectInfo()

        {

            //(1)doing something here for field initializing

            //(2)说明:不要在构造函数中为ICommand对象进行初始化,ICommand对象的初始化直接放到其属性的get方法中

            //(3)以下是对事件关注的代码

            //OnSerialized(default(StreamingContext)); //对关注事件的处理.StreamingContext是结构体。另一种方法是直接在此处放置代码

            EventInitializer();     //用这个更简洁一些,无需在每次调用构造函数的时候都创建一个default(StreamingContext)

        }

        [OnDeserializing]

        private void OnSerializing(StreamingContext context)

        {

        }

        [OnDeserialized]

        private void OnSerialized(StreamingContext context)

        {

                //这个方法中,可以为关注事件填写相关代码

                EventRemedy();

                EventInitialzier();  //构造函数中也会调用的代码

        }

            private void EventRemedy()

                {

                        //这个方法仅可以被OnDeserialized调用。

                        //由于程序之前在添加集合对象或关联对象的时候,可能关注了事件,但是由于反序列化程序不会去重新执行一次上面的有关程序代码,因此当反序列化后就会漏掉了对这些集合对象条目或关联对象的事件关注。因此,这里需要采取补救措施。也就是对已经存在的这些集合对象条目或关联对象进行事件的关注。比如原来有个ObservableCollection<Child>属性,在AddChild函数中关注了Child的XXXEvent事件,反序列化完成的时候,这个关注的信息就丢失了,因此这里要补充关注一下

                }

            private void EventInitializer()

                {

                    //用于在构造函数中执行的关注事件的代码

                }

        [field:NonSerialized]    

        public event EventHandler MyEvent;

        [NonSerialized]    

        private ICommand _myCommand;

        public ICommand MyCommand

        {

            get

            {

                    if(_myCommand==null)

                        _myCommand=new DelegateCommand(MyCommandHandler);  //命令对象的初始化

                    return _myCommand;

            }

        }

        private void MyCommandHandler()

        {

                //concrete logical code for MyCommand

        }

    }

    (4)****非常重要****。需要说明的是,反序列化的过程(从文件-->对象的过程),不是new出来新对象,然后对其进行赋值的。反序列化的时候,不是依据类代码对各个成员进行初步赋值,然后执行构造函数的过程。在反序列化的时候,既不会为成员初赋值,也不会执行构造函数。例如:

    [Serializable]

    public class MyClass

    {

            public MyClass()

            {

                //在反序列化的时候,不会执行构造函数

            }

            private int x=10;   //在反序列化的时候,不是将10赋值给x。而是从数据文件中读取相应的值,直接赋值给x。

           [NonSerializable]

           private int y=15;   //在反序列化的时候,不会将15赋值给y。由于y标注了[NonSerializable],因此,反序列化完成的时候,y的值是default(int),也就是0。

            private List<string> Strs=new List<string>();  //在反序列化的时候,不会new一个将List<string>并且赋值给Strs。而是从数据文件中读取相应的值,直接赋值给Strs。

           [NonSerializable]

            private List<string> AnotherStrs=new List<string>();  //在反序列化的时候,不会new一个将List<string>并且赋值给AnotherStrs。由于AnotherStrs标注了[NonSerializable],因此,反序列化完成的时候,AnotherStrs的值是default(List<string>),也就是null。

    }

    (四)***非常重要***:OnSerializing和OnDeserilized方法与类的继承

        (1) 当类B继承于类A的时候(即B是A的子类),如果A和B中都包含OnSerializing和OnDeserialized方法,这里分两种情况。

                 (A)父类A和子类B中的OnSerializing和OnDeserialized方法都是私有的,则执行的顺序为:

                        (*)在序列化的时候,先执行父类的OnSerializing,,然后执行子类的OnSerializing。

                        (*)在反序列化的时候,先执行父类的OnDeserialized,,然后执行子类的OnDeserialized。

                         ----也就是说,上面这种情况,无论是序列化还是反序列化,都是先执行父类中的方法,然后执行子类中的方法。-

                (B)如果父类中的方法是protected或public,则必须加上virtual,然而实际情况是,如果加上virtual,则程序无法运行。也就是OnSerializing和OnDeserialized方法都不存在子类覆写(override)父类方法的情况,否则是无法运行的(visual studio显示:应用程序处于中断模式)。

           (2)如果父类中存在OnSerializing和OnDeserialized方法,且方法都是父类私有的,即private。那么在序列化和反序列化的时候,父类中的OnSerializing和OnDeserialized依旧会执行的。当然,如果把private修改为protected或public,结果是一样的。这里可以看出,如果从面向对象的角度看,父类中的private是不能被子类调用的,但实际上还是调用了,实际上这是系统调用的,不是子类调用的。和面向对象思想不同,虽然是父类的私有方法,照样会被调用。

           (3)如果子类中存在OnSerializing和OnDeserialized方法,而父类中不存在这些方法,且是私有的即private。那么在序列化和反序列化的时候,子类中的OnSerializing和OnDeserialized依旧会执行的。   当然,如果把private修改为protected或public,结果也是一样的。   

    (五)一些不能被序列化的字段的处理方法

         对于采用类库中的一些类型(如WPF程序常用的SolidColorBrush,TranslateTransform,ScaleTransform,RotateTransform),由于这些类库中的类型没有被开发厂商标注为Serializable的类型,因此无法序列化到文件中。在程序中用到的时候,如果使用它们的类型要实现序列化,就比对给这些类型加上[NonSerialized],程序才能编译通过。但这样一来,在序列化的时候就会丢失数据,怎么办?可行的方法之一就是给程序加上OnSerializing和OnSerialized方法,并增加可以被序列化的字段(记作TransferDataField)用于保存这些无法被序列化类型中的关键数据。也就是说,在OnSerializing方法中,将无法序列化的[NonSerialized]字段中的关键数据保存到TransferDataField,在OnSerialized方法中,利用TransferDataField字段中的数据重新new出来一个对象赋值给无法序列化的[NonSerialized]字段。如下所示,对一些字段进行序列化处理方式。

            [OnSerializing]
            protected virtual void OnSerializing(StreamingContext context)
            {
                
                if (rtData == null || rtData.Length != 3)
                    rtData = new double[3];
                rtData[0] = _rotateTransform.Angle;
                rtData[1] = _rotateTransform.CenterX;
                rtData[2] = _rotateTransform.CenterY;


                if (ttData == null || ttData.Length != 2)
                    ttData = new double[2];
                ttData[0] = _translateTransform.X;
                ttData[1] = _translateTransform.Y;


                if (stData == null || stData.Length != 4)
                    stData = new double[4];
                stData[0] = _scaleTransform.ScaleX;
                stData[1] = _scaleTransform.ScaleY;
                stData[2] = _scaleTransform.CenterX;
                stData[3] = _scaleTransform.CenterY;


                auxiliaryElementLineStrokeData=_auxiliaryElementLineStroke.Color.ToString();
                strokeData=_stroke.Color.ToString();
            }


            [OnDeserialized]
            protected virtual void OnDeserialized(StreamingContext context)
            {
                if (rtData != null && rtData.Length == 3)
                    _rotateTransform = new RotateTransform(rtData[0], rtData[1], rtData[2]);


                if (ttData != null && ttData.Length == 2)
                    _translateTransform = new TranslateTransform(ttData[0], ttData[1]);


                if (stData != null && stData.Length == 4)
                    _scaleTransform = new ScaleTransform(stData[0], stData[1], stData[2], stData[3]);


                _transformGroup = new TransformGroup();
                TransformGroup.Children.Add(ScaleTransform);
                TransformGroup.Children.Add(TranslateTransform);


                BrushConverter brushConverter = new BrushConverter();
     _auxiliaryElementLineStroke = (SolidColorBrush)brushConverter.ConvertFromString(auxiliaryElementLineStrokeData);
                _stroke = (SolidColorBrush)brushConverter.ConvertFromString(strokeData);
            }
            // TransferDateField.用于存储RotateTransform、TranslateTranslate和ScaleTransform的数据,便于反序列化.
            private double[] rtData,ttData, stData;
            // TransferDateField.用于存储_auxiliaryElementLineStroke、_stroke的数据,便于反序列化.
            private string auxiliaryElementLineStrokeData, strokeData;


            [NonSerialized]
            private RotateTransform _rotateTransform=new RotateTransform();
            public RotateTransform RotateTransform
            {
                get { return _rotateTransform; }
                set
                {
                    _rotateTransform = value;
                }
            }
            [NonSerialized]
            private TranslateTransform _translateTransform = new TranslateTransform();
            public TranslateTransform TranslateTransform
            {
                get { return _translateTransform; }
            }
            [NonSerialized]
            private ScaleTransform _scaleTransform = new ScaleTransform();
            public ScaleTransform ScaleTransform
            {
                get { return _scaleTransform; }
            }


            [NonSerialized]
            private SolidColorBrush _auxiliaryElementLineStroke = new SolidColorBrush(Colors.Gray);
            public SolidColorBrush AuxiliaryElementLineStroke
            {
                get
                {
                    return _auxiliaryElementLineStroke;
                }
                set
                {
                    _auxiliaryElementLineStroke = value;
                    OnPropertyChanged("AuxiliaryElementLineStroke");
                }
            }
            [NonSerialized]
            private SolidColorBrush _stroke = new SolidColorBrush(Colors.Black);
            public virtual SolidColorBrush Stroke
            {
                get { return _stroke; }
                set
                {
                    _stroke = value;
                    OnPropertyChanged("Stroke");
                }
            }

    (六)选用方式

    对于应用程序需要保存为文件的情况,我个人倾向于BinaryFormatter,而不是XmlSerializer,因为后者不能对私有和保护级别的字段进行序列化。对于需要网络传输的Web Api数据,我个人倾向于XmlSerializer。

    (补充:事件一定要用加上特性[field:NonSerialized],要不然在序列化的时候,会需要一起序列化订阅者对象,导致无法序列化的异常,曾经采坑并为此找了好久原因。比如在UI对象中订阅ViewModel中的对象的事件,则会需要序列化UI对象,而这是不正确的,会导致错误。)

    展开全文
  • 1.说明:Dictionary对象本身不支持序列化反序列化,需要定义一个继承自Dictionary, IXmlSerializable类的自定义类来实现该功能。感觉完全可以把这样的类封装到C#库中,很具有通用性嘛,至今没有遇到不能用的情况的...

    1.说明:Dictionary对象本身不支持序列化和反序列化,需要定义一个继承自Dictionary, IXmlSerializable类的自定义类来实现该功能。感觉完全可以把这样的类封装到C#库中,很具有通用性嘛,至今没有遇到不能用的情况的说,或许出于其他方面的考虑microsoft才没有这么做。


    2.SerializableDictionary自定义类

        [Serializable]
        public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
        {
            public SerializableDictionary() { }
            public void WriteXml(XmlWriter write)       // Serializer
            {
                XmlSerializer KeySerializer = new XmlSerializer(typeof(TKey));
                XmlSerializer ValueSerializer = new XmlSerializer(typeof(TValue));
    
                foreach (KeyValuePair<TKey, TValue> kv in this)
                {
                    write.WriteStartElement("SerializableDictionary");
                    write.WriteStartElement("key");
                    KeySerializer.Serialize(write, kv.Key);
                    write.WriteEndElement();
                    write.WriteStartElement("value");
                    ValueSerializer.Serialize(write, kv.Value);
                    write.WriteEndElement();
                    write.WriteEndElement();
                }
            }
            public void ReadXml(XmlReader reader)       // Deserializer
            {
                reader.Read();
                XmlSerializer KeySerializer = new XmlSerializer(typeof(TKey));
                XmlSerializer ValueSerializer = new XmlSerializer(typeof(TValue));
    
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    reader.ReadStartElement("SerializableDictionary");
                    reader.ReadStartElement("key");
                    TKey tk = (TKey)KeySerializer.Deserialize(reader);
                    reader.ReadEndElement();
                    reader.ReadStartElement("value");
                    TValue vl = (TValue)ValueSerializer.Deserialize(reader);
                    reader.ReadEndElement();
                    reader.ReadEndElement();
                    this.Add(tk, vl);
                    reader.MoveToContent();
                }
                reader.ReadEndElement();
    
            }
            public XmlSchema GetSchema()
            {
                return null;
            }
        }

    3.使用

      a.定义SerializableDictionary对象,这里以存储<string,string>键对为例:

    SerializableDictionary<string, string> serializableDictionary = new SerializableDictionary<string, string>();

      b.添加元素

    serializableDictionary.Add("Key1", “Value1”);
    ......

      c.序列化

                using (FileStream fileStream = new FileStream(fileName, FileMode.Create))
                {
                    XmlSerializer xmlFormatter = new XmlSerializer(typeof(SerializableDictionary<string, string>));
                    xmlFormatter.Serialize(fileStream, this.serializableDictionary);
                }
        注:文件名fileName自己定义,如“file.xml”

      d.反序列化

                using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
                {
                    XmlSerializer xmlFormatter = new XmlSerializer(typeof(SerializableDictionary<string, string>));
                    this.serializableDictionary = (SerializableDictionary<string,string>)xmlFormatter.Deserialize(fileStream);
                }
     

     

    展开全文
  • MSDN注解:允许对象控制其自己的序列化反序列化过程。 ISerializable 接口的定义: public interface ISerializable { void GetObjectData(SerializationInfo info, StreamingContext context); } 意思...

    ISerializable 接口

    MSDN注解:允许对象控制其自己的序列化和反序列化过程。

    ISerializable 接口的定义:

    public interface ISerializable
    {
        void GetObjectData(SerializationInfo info, StreamingContext context);
    }

    意思就是我们可以通过实现 ISerializable 接口来控制序列化与反序列化后的结果。但是只有使用 BinaryFormatter 时才有用。使用 JavaScriptSerializer 类并没有效果。下面通过一个示例学习一下。

    示例

    定义实现 ISerializable 接口的类:

    [Serializable]  //记得标记此 Attribute
    public class Product : ISerializable
    {
        private string _name;
        public Product() { }
    
        public Product(SerializationInfo info, StreamingContext context)
        {
            _name = (String)info.GetValue("Name", typeof(String));
        }
    
        public String Name
        {
            get { return this._name; }
            set { this._name = value; }
        }
    
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Name", "JRoger.NET",typeof(String));
        }
    }

     通过 BinaryFormatter 序列化和反序列化此类:

    [Test]
    public void SerializableTest()
    {
        var product = new Product { Name = "Hello" };
        var formatter = new BinaryFormatter();
        var stream = File.Open(@"E:\Log.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite);
    
        formatter.Serialize(stream, product);
    
        stream.Close();
        stream.Dispose();
    
        var obj = (Product)formatter.Deserialize(File.Open(@"E:\Log.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite));
    
        Trace.WriteLine(obj.Name);
    }

     可以看到,实例化 Product 类时,Name 属性的值为 "Hello" 而反序列化后输出结果却为 "JRoger.NET"。其实控制序列化和反序列化结果的关键就是实现 ISerializable 接口。另外实现 ISerializable 接口的类还要有一个带有两个参数的构造函数,这两个参数的类型分别为: SerializationInfoStreamingContext 。

    总结

    总的来说实现上很简单,配上示例也很容易。但是使用自定义序列化和反序列化的场景可能并不多。不过作为学习内容还是很有必要的。使用场景少,并不代表没有。不要放过任何细节。

    展开全文
  • c#序列化反序列化

    2016-10-11 08:41:31
    1.对象序列化的介绍 (1).NET支持对象序列化的几种方式 二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Serialization.Formatters.Binary命名空间下。...

    1.对象序列化的介绍

    (1).NET支持对象序列化的几种方式

    二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Serialization.Formatters.Binary命名空间下。

    SOAP序列化:对象序列化之后的结果符合SOAP协议,也就是可以通过SOAP 协议传输,通过System.Runtime.Serialization.Formatters.Soap命名空间下的SoapFormatter类来实现的。

    XML序列化:对象序列化之后的结果是XML形式的,通过XmlSerializer 类来实现的,这个类位于System.Xml.Serialization命名空间下。XML序列化不能序列化私有数据。

    (2)几种序列化的区别

    二进制格式和SOAP格式可序列化一个类型的所有可序列化字段,不管它是公共字段还是私有字段。XML格式仅能序列化公共字段或拥有公共属性的私有字段,未通过属性公开的私有字段将被忽略。

    使用二进制格式序列化时,它不仅是将对象的字段数据进行持久化,也持久化每个类型的完全限定名称和定义程序集的完整名称(包括包称、版本、公钥标记、区域性),这些数据使得在进行二进制格式反序列化时亦会进行类型检查。SOAP格式序列化通过使用XML命名空间来持久化原始程序集信息。而XML格式序列化不会保存完整的类型名称或程序集信息。这便利XML数据表现形式更有终端开放性。如果希望尽可能延伸持久化对象图的使用范围时,SOAP格式和XML格式是理想选择。

    (3)使用特性对序列化的控制

    要让一个对象支持.Net序列化服务,用户必须为每一个关联的类加上[Serializable]特性。如果类中有些成员不适合参与序列化(比如:密码字段),可以在这些域前加上[NonSerialized]特性。

    2.使用二进制序列化和反序列化

    (1)二进制序列化与反序列化的程序示例

        [Serializable]  //必须添加序列化特性

        public class Person

        {

            private string Name;//姓名

            private bool Sex;//性别,是否是男

            public Person(string name, bool sex)

            {

                this.Name = name;

                this.Sex = sex;

            }

            public override string ToString()

            {

                return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");

            }

        }

        [Serializable]  //必须添加序列化特性

        public class Programmer : Person

        {

            private string Language;//编程语言

            public Programmer(string name, bool sex, string language) : base(name, sex)

            {

                this.Language = language;

            }

            public override string ToString()

            {

                return base.ToString() + "\t编程语言:" + this.Language;

            }

        }

        class Program

        {

            static void Main(string[] args)

            {

                //创建Programmer列表,并添加对象

                List<Programmer> list = new List<Programmer>();

                list.Add(new Programmer("李志伟", true, "C#"));

                list.Add(new Programmer("Coder2", false, "C++"));

                list.Add(new Programmer("Coder3", true, "Java"));

                //使用二进制序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.dat";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);

                BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器

                binFormat.Serialize(fStream, list);

                //使用二进制反序列化对象

                list.Clear();//清空列表

                fStream.Position = 0;//重置流位置

                list = (List<Programmer>)binFormat.Deserialize(fStream);//反序列化对象

                foreach (Programmer p in list)

                {

                    Console.WriteLine(p);

                }

                Console.Read();

            }

        }

    (2)总结

    使用二进制序列化,必须为每一个要序列化的的类和其关联的类加上[Serializable]特性,对类中不需要序列化的成员可以使用[NonSerialized]特性。

    二进制序列化对象时,能序列化类的所有成员(包括私有的),且不需要类有无参数的构造方法。

    使用二进制格式序列化时,它不仅是将对象的字段数据进行持久化,也持久化每个类型的完全限定名称和定义程序集的完整名称(包括包称、版本、公钥标记、区域性),这些数据使得在进行二进制格式反序列化时亦会进行类型检查。所以反序列化时的运行环境要与序列化时的运行环境要相同,否者可能会无法反序列化成功。

    3.使用SOAP方式序列化和反序列化

    (1)SOAP序列化与反序列化的程序示例

        [Serializable]  //必须添加序列化特性

        public class Person

        {

            private string Name;//姓名

            private bool Sex;//性别,是否是男

            public Person(string name, bool sex)

            {

                this.Name = name;

                this.Sex = sex;

            }

            public override string ToString()

            {

                return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");

            }

        }

        [Serializable]  //必须添加序列化特性

        public class Programmer : Person

        {

            private string Language;//编程语言

            public Programmer(string name, bool sex, string language) : base(name, sex)

            {

                this.Language = language;

            }

            public override string ToString()

            {

                return base.ToString() + "\t编程语言:" + this.Language;

            }

        }

        class Program

        {

            static void Main(string[] args)

            {

                //实例化对象

                Programmer p = new Programmer("李志伟", true, "C、C#、C++、Java");

                //使用SOAP序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);

                SoapFormatter soapFormat = new SoapFormatter();//创建SOAP序列化器

                soapFormat.Serialize(fStream, p);//SOAP不能序列化泛型对象

                //使用SOAP反序列化对象

                fStream.Position = 0;//重置流位置

                p = null;

                p = (Programmer)soapFormat.Deserialize(fStream);

                Console.WriteLine(p);

                Console.Read();

            }

        }

    (2)总结

    SOAP序列化与二进制序列化的区别是:SOAP序列化不能序列化泛型类型。与二进制序列化一样在序列化时不需要向序列化器指定序列化对象的类型。而XML序列化需要向XML序列化器指定序列化对象的类型。

    4.使用XML方式序列化和反序列化

    (1)XML序列化与反序列化的程序示例

        public class Person

        {

            public string Name;//姓名

            public bool Sex;//性别,是否是男

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

            public Person(string name, bool sex)

            {

                this.Name = name;

                this.Sex = sex;

            }

            public override string ToString()

            {

                return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");

            }

        }

        public class Programmer : Person

        {

            public string Language;//编程语言

            public Programmer() { }//必须提供无参构造器,否则XmlSerializer将出错

            public Programmer(string name, bool sex, string language) : base(name, sex)

            {

                this.Language = language;

            }

            public override string ToString()

            {

                return base.ToString() + "\t编程语言:" + this.Language;

            }

        }

        class Program

        {

            static void Main(string[] args)

            {

                //创建Programmer列表,并添加对象

                List<Programmer> list = new List<Programmer>();

                list.Add(new Programmer("李志伟", true, "C#"));

                list.Add(new Programmer("Coder2", false, "C++"));

                list.Add(new Programmer("Coder3", true, "Java"));

                //使用XML序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);

                XmlSerializer xmlFormat = new XmlSerializer(

    typeof(List<Programmer>),

    new Type[] { typeof(Programmer),typeof(Person) }

    );//创建XML序列化器,需要指定对象的类型

                xmlFormat.Serialize(fStream, list);

                //使用XML反序列化对象

                fStream.Position = 0;//重置流位置

                list.Clear();

                list = (List<Programmer>)xmlFormat.Deserialize(fStream);

                foreach (Programmer p in list)

                {

                    Console.WriteLine(p);

                }

                Console.Read();

            }

        }

    (2)总结

    使用XML序列化或反序列化时,需要对XML序列化器指定需要序列化对象的类型和其关联的类型。

    XML序列化只能序列化对象的公有属性,并且要求对象有一个无参的构造方法,否者无法反序列化。

    [Serializable]和[NonSerialized]特性对XML序列化无效!所以使用XML序列化时不需要对对象增加[Serializable]特性。

    5.XML序列化对象详解

    (1)说明

    本节主要介绍:使用特性控制对象序列化成XML文件的格式。

    (2)使用XmlElement(默认值)

    类声明:

        public class Person

        {

            [XmlElement]

            public string Name;//使用[XmlElement]特性

            public bool Sex;//默认使用了[XmlElement]特性

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

    序列化生成的XML文件:

    <Personxmlns:xsi="..."xmlns:xsd="...">

      <Name>李志伟</Name>

      <Sex>true</Sex>

    </Person>

    (3)使用XmlAttribute

    类声明:

        public class Person

        {

            [XmlElement]

            public string Name;

            [XmlAttribute]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

    序列化生成的XML文件:

    <Personxmlns:xsi="..."xmlns:xsd="..."Sex="true">

      <Name>李志伟</Name>

    </Person>

    (4)使用XmlText

    类声明:

        public class Person

        {

            [XmlText]

            public string Name;

            [XmlAttribute]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

    序列化生成的XML文件:

    <Personxmlns:xsi="..."xmlns:xsd="..."Sex="true">李志伟</Person>

    (5)使用XmlType和XmlAttribute(重命名节点名称)

    类声明:

        [XmlType("个人信息")]

        public class Person

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

    序列化生成的XML文件:

    <个人信息xmlns:xsi="..."xmlns:xsd="..."姓名="李志伟"性别="true" />

    (6)列表和数组的序列化

    类声明:

        [XmlType("个人信息")]

        public class Person

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        class Program

        {

            static void Main(string[] args)

            {

                Person p = new Person();

                p.Name = "李志伟";

                p.Sex = true;

                Person[] ps = new Person[3];

                ps[0] = p;

                ps[1] = p;

                ps[2] = p;

                //使用XML序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create);

                XmlSerializer xmlFormat = new XmlSerializer(typeof(Person[]));

                xmlFormat.Serialize(fStream, ps);//序列化对象

                fStream.Dispose();//关闭文件

                Console.WriteLine("OK!");

                Console.Read();

            }

        }

    序列化生成的XML文件:

    <ArrayOf个人信息xmlns:xsi="..."xmlns:xsd="...">

      <个人信息姓名="李志伟"性别="true" />

      <个人信息姓名="李志伟"性别="true" />

      <个人信息姓名="李志伟"性别="true" />

    </ArrayOf个人信息>

    注意:发现此时的XML文件的根节点名称变了。此时要重命名根节点应使用如下方式:

        [XmlType("个人信息")]

        public class Person

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        [XmlType("人员信息")]

        public class PersonArray : List<Person> { }

        class Program

        {

            static void Main(string[] args)

            {

                Person p = new Person();

                p.Name = "李志伟";

                p.Sex = true;

                PersonArray ps = new PersonArray();

                ps.Add(p);

                ps.Add(p);

                ps.Add(p);

                //使用XML序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create);

                XmlSerializer xmlFormat = new XmlSerializer(typeof(PersonArray));

                xmlFormat.Serialize(fStream, ps);//序列化对象

                fStream.Dispose();//关闭文件

                Console.WriteLine("OK!");

                Console.Read();

            }

        }

    序列化生成的XML文件:

    <人员信息xmlns:xsi="..."xmlns:xsd="...">

      <个人信息姓名="李志伟"性别="true" />

      <个人信息姓名="李志伟"性别="true" />

      <个人信息姓名="李志伟"性别="true" />

    </人员信息>

    (7)列表和数组的做为数据成员的序列化

    类声明:

        [XmlType("信息")]

        public class Person

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        public class PersonArray

        {

            public List<Person> Array=new List<Person>();

            public Person Person = new Person();

        }

        class Program

        {

            static void Main(string[] args)

            {

                PersonArray ps = new PersonArray();

                ps.Person = new Person();

                ps.Person.Name = "李志伟";

                ps.Person.Sex = true;

                ps.Array.Add(ps.Person);

                ps.Array.Add(ps.Person);

                ps.Array.Add(ps.Person);

                //使用XML序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create);

                XmlSerializer xmlFormat = new XmlSerializer(typeof(PersonArray));

                xmlFormat.Serialize(fStream, ps);//序列化对象

                fStream.Dispose();//关闭文件

                Console.WriteLine("OK!");

                Console.Read();

            }

        }

    序列化生成的XML文件:

    <PersonArrayxmlns:xsi="..."xmlns:xsd="...">

      <Array>

        <个人信息姓名="李志伟"性别="true" />

        <个人信息姓名="李志伟"性别="true" />

        <个人信息姓名="李志伟"性别="true" />

      </Array>

      <Person姓名="李志伟"性别="true" />

    </PersonArray>

    注意:假设这里需要为Array和Person的节点重命名,代码如下:

        [XmlType("信息")]

        public class Person

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        public class PersonArray

        {

            [XmlArrayItem("个人信息")]

            [XmlArray("人员信息")]

            public List<Person> Array=new List<Person>();

            public Person Person = new Person();

        }

    序列化生成的XML文件:

    <PersonArrayxmlns:xsi="..."xmlns:xsd="...">

      <人员信息>

        <个人信息姓名="李志伟"性别="true" />

        <个人信息姓名="李志伟"性别="true" />

        <个人信息姓名="李志伟"性别="true" />

      </人员信息>

      <Person姓名="李志伟"性别="true" />

    </PersonArray>

    注意:把“人员信息”节点去掉呢(直接出现“个人信息”节点)

        [XmlType("信息")]

        public class Person

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        public class PersonArray

        {

            [XmlElement("个人信息")]

            public List<Person> Array=new List<Person>();

            public Person Person = new Person();

        }

    序列化生成的XML文件:

    <PersonArrayxmlns:xsi="..."xmlns:xsd="...">

      <个人信息姓名="李志伟"性别="true" />

      <个人信息姓名="李志伟"性别="true" />

      <个人信息姓名="李志伟"性别="true" />

      <Person姓名="李志伟"性别="true" />

    </PersonArray>

    (8)类型继承与反序列化

    类声明:

        public class Base { }

        [XmlType("信息A")]

        public class PersonA : Base

        {

            [XmlAttribute("姓名")]

            public string Name;

            [XmlAttribute("性别")]

            public bool Sex;

            public PersonA() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        [XmlType("信息B")]

        public class PersonB : Base

        {

            [XmlElement("姓名")]

            public string Name;

            [XmlElement("年龄")]

            public int Age;

            public PersonB() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

        [XmlType("人员信息")]

        public class PersonArray

        {

            [XmlArrayItem(typeof(PersonA)), XmlArrayItem(typeof(PersonB))]

            public List<Base> ListPerson=new List<Base>();

        }

        class Program

        {

            static void Main(string[] args)

            {

                PersonA pa = new PersonA();

                pa.Name = "李志伟A";

                pa.Sex = true;

                PersonB pb = new PersonB();

                pb.Name = "李志伟B";

                pb.Age = 21;

                PersonArray ps = new PersonArray();

                ps.ListPerson.Add(pa);

                ps.ListPerson.Add(pa);

                ps.ListPerson.Add(pb);

                ps.ListPerson.Add(pb);

                //使用XML序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create);

                XmlSerializer xmlFormat = new XmlSerializer(typeof(PersonArray));

                xmlFormat.Serialize(fStream, ps);//序列化对象

                fStream.Dispose();//关闭文件

                Console.WriteLine("OK!");

                Console.Read();

            }

        }

    序列化生成的XML文件:

    <人员信息xmlns:xsi="..."xmlns:xsd="...">

      <ListPerson>

        <信息A姓名="李志伟A"性别="true" />

        <信息A姓名="李志伟A"性别="true" />

        <信息B>

          <姓名>李志伟B</姓名>

          <年龄>21</年龄>

        </信息B>

        <信息B>

          <姓名>李志伟B</姓名>

          <年龄>21</年龄>

        </信息B>

      </ListPerson>

    </人员信息>

    注意:同时为列表成员指定多个[XmlArrayItem(typeof(XXX))]可实现多种派生类型混在一起输出。

    (9)排除不需要序列化的成员

    类声明:

        public class Person

        {

            public string Name;

            [XmlIgnore]// 这个属性将不会参与序列化

            public bool Sex;

            public Person() { }

        }

    序列化生成的XML文件:

    <Personxmlns:xsi="..."xmlns:xsd="...">

      <Name>李志伟</Name>

    </Person>

    (10)强制指定成员的序列化顺序

    类声明:

        public class Person

        {

            [XmlElement(Order = 2)]

            public string Name;

            [XmlElement(Order = 1)]

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        }

    序列化生成的XML文件:

    <Personxmlns:xsi="..."xmlns:xsd="...">

      <Sex>true</Sex>

      <Name>李志伟</Name>

    </Person>

    (11)自定义序列化行为

    类声明:

        public class Person : IXmlSerializable

        {

            public string Name;

            public bool Sex;

            public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

            public System.Xml.Schema.XmlSchema GetSchema()

            {

                return null;

            }

            public void ReadXml(System.Xml.XmlReader reader)

            {

                Name = reader.GetAttribute("姓名");

                Sex = reader.GetAttribute("性别").Equals("男") ? true : false;

            }

            public void WriteXml(System.Xml.XmlWriter writer)

            {

                writer.WriteAttributeString("姓名", Name);

                writer.WriteAttributeString("性别", Sex ? "男" : "女");

            }

        }

    序列化生成的XML文件:

    <Person姓名="李志伟"性别="男" />

    (12)序列化设置XML命名空间

    类声明:

        [XmlRoot(Namespace = "http://msdn.microsoft.com/vsdh.xsd")]

        public class Person

        {

            public string Name;

            public bool Sex;

            public Person() { }

        }

    序列化生成的XML文件:

    <Personxmlns:xsi="..."xmlns:xsd="..."xmlns="http://msdn.microsoft.com/vsdh.xsd">

      <Name>李志伟A</Name>

      <Sex>true</Sex>

    </Person>

    (13)XML的使用建议

    在服务端,C#代码中:

    1. 建议不用使用低级别的XML API来使用XML,除非你是在设计框架或者通用类库。

    2. 建议使用序列化、反序列化的方法来生成或者读取XML

    3. 当需要考虑使用XML时,先不要想着XML结构,先应该定义好数据类型。

    4. 列表节点不要使用[XmlElement],它会让所有子节点【升级】,显得结构混乱。

    5. 如果希望序列化的XML长度小一点,可以采用[XmlAttribute],或者指定一个更短小的别名。

    6. 不要在一个列表中输出不同的数据类型,这样的XML结构的可读性不好。

    7. 尽量使用UTF-8编码,不要使用GB2312编码。

    在客户端,JavaScript代码中,我不建议使用XML,而是建议使用JSON来代替XML,因为:

    1. XML文本的长度比JSON要长,会占用更多的网络传输时间(毕竟数据保存在服务端,所以传输是免不了的)。

    2. 在JavaScritp中使用XML比较麻烦(还有浏览器的兼容问题),反而各种浏览器对JSON有非常好的支持。

    (14)反序列化的使用总结

    如果XML是由类型序列化得到那的,那么反序列化的调用代码是很简单的,反之,如果要面对一个没有类型的XML,就需要我们先设计一个(或者一些)类型出来,这是一个逆向推导的过程,请参考以下步骤:

    1. 首先要分析整个XML结构,定义与之匹配的类型,

    2. 如果XML结构有嵌套层次,则需要定义多个类型与之匹配,

    3. 定义具体类型(一个层级下的XML结构)时,请参考以下表格。

    XML形式

    处理方法

    补充说明

    XmlElement

    定义一个属性

    属性名与节点名字匹配

    XmlAttribute

    [XmlAttribute] 加到属性上

     

    InnerText

    [InnerText] 加到属性上

    一个类型只能使用一次

     

     

    节点重命名

    根节点:[XmlType("testClass")] 
    元素节点:[XmlElement("name")] 
    属性节点:[XmlAttribute("id")] 
    列表子元素节点:[XmlArrayItem("Detail")] 
    列表元素自身:[XmlArray("Items")]

     

    6.自定义序列化(仅适用于二进制与SOAP)

    (1)自定义序列化的实现方式

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

    (2)示例程序

        [Serializable]

        public class Person : ISerializable

        {

            public string Name;

            public bool Sex;

            public Person() { }

            //必须的够着方法,反序列化时调用

            protected Person(SerializationInfo info, StreamingContext context)

            {

                Name = info.GetString("姓名");

                Sex = info.GetBoolean("性别");

            }

            //序列化时调用

            public void GetObjectData(SerializationInfo info, StreamingContext context)

            {

                info.AddValue("姓名", Name + "(自定义序列化)");

                info.AddValue("性别", Sex);

            }

            public override string ToString()

            {

                return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");

            }

        }

        class Program

        {

            static void Main(string[] args)

            {

                Person p = new Person();

                p.Name = "李志伟A";

                p.Sex = true;

                //使用二进制序列化对象

                string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

                Stream fStream = new FileStream(fileName, FileMode.Create);

                BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器

                binFormat.Serialize(fStream, p);//序列化对象

                //使用二进制反序列化对象

                fStream.Position = 0;//重置流位置

                p = (Person)binFormat.Deserialize(fStream);//反序列化对象

                Console.WriteLine(p);

                fStream.Dispose();//关闭文件

                Console.WriteLine("OK!");

                Console.Read();

            }

        }

    注意:在序列化过程中调用 GetObjectData()时,需要填充方法调用中提供的SerializationInfo对象。只需按名称/值对的形式添加将要序列化的变量。其名称可以是任何文本。只要已序列化的数据足以在反序列化过程中还原对象,便可以自由选择添加至SerializationInfo 的成员变量。如果基对象实现了 ISerializable,则派生类应调用其基对象的 GetObjectData()方法。同样,在反序列化时也会调用含有(SerializationInfo info, StreamingContextcontext)参数的特殊的够着方法!否者将无法反序列化!!!

    展开全文
  • //XML命名空间,可用于与反序列化方法中指定当前节点的前缀,需要注意的是,此方法指定命名空间所修改的前缀对当前节点包含的所有子节点生效,对当前节点本身不生效,当前节点的前缀继承父节点 [XmlRoot(Namespace = ...
  • 背景今天在使用:C# Json 序列化反序列化 反序列化的时候出现了下面的错误信息。 System.Runtime.Serialization.SerializationException: 数据协定类型“TestEntity”无法反序列化,因为未找到必需的数据成员...
  • 一、序列化反序列化的概念  把对象转换为字节序列的过程称为对象的序列化。  把字节序列恢复为对象的过程称为对象的反序列化。  对象的序列化主要有两种用途:  1) 把对象的字节序列永久地保存到硬盘上,...
  • C#序列化(Serialize)、反序列化(Deserialize)  序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方...
  • C#对象序列化反序列化 C#对象序列化反序列化(转载自:http://www.cnblogs.com/LiZhiW/p/3622365.html) 1. 对象序列化的介绍.................................................................... 2 ...
  • C# 序列化反序列化

    2017-06-23 15:54:21
    反序列化:将二进制转换为对象 目的:传输数据(网络中传输数据的形式) 只有被[serializable]标记的类创建的对象才可以被序列化;但是这个类不可以被继承。 通过一个流将一个二进制文件写入到指定目的;再进过...
  • C#可以序列化一个对象为流,也可以把流序列化为一个对象。本文分析了类型定义变化后不影响反序列化的几种情况。
  • C# 三种序列化方法分享 作者: 这篇文章主要介绍了C# 三种序列化方法,需要的朋友可以参考下 序列化是将一个对象转换成字节流以达到将其长期保存在内存、数据库或文件中的处理过程。它的主要目的是保存...
  • 序列化反序列化 序列化反序列化 序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程,其逆过程一般称为反序列化。 格式化器 使用命名空间System.Runtime.Serialization.Formatters....
  • .net序列化反序列化 序列化是指一个对象的实例可以被保存,保存成一个二进制串,当然,一旦被保存成二进制串,那么也可以保存成文本串了。比如,一个计数器,数值为2,我们可以用字符串“2”表示。如果有个...
  • 转自:https://www.cnblogs.com/sandyliu1999/p/4844664.htmlC#: .net序列化反序列化 [XmlElement(“节点名称”)] [XmlAttribute(“节点属性”)] (上篇).net序列化反序列化序列化是指一个对象的实例可以被保存...
  • 最近需要写一个存储对象和加载对象的对象序列化功能. 记录一下这个这个过程: 首先是有个要被序列化存储的对象: public class ObjModel{  public String Name{get;set; }  public String Value{ get...
  • public class User { public Guid _id { get; set; } public Log L { get;... [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions...上述这样的结构在MongoDB C#驱动中无法被反序列化,请教如何结果?
  • c#序列化和反射(摘抄)

    2019-07-16 20:28:07
    序列化反序列化的作用是:使数据能够被轻松的存储和传输。 在.net框架里提供了这样两个类: BinaryFormatter:使用二进制格式化程序进行序列化。 SoapFormatter:以xml格式化 XmlSerializer类 DotNet中的序列化...
1 2 3 4 5 ... 20
收藏数 23,739
精华内容 9,495