clr via c# 运行时序列化

1,快速了解序列化----windows IO 系统,FileStream,BinaryFormatter,SoapFormatter--不支持泛型.

public class SerializeRef
    {
        public static void CallQuick()
        {
            dynamic objectgrap = new List<string>() { "jeff", "kristin", "aldan", "grant" }.ToArray<string>();

            using (var st = new FileStream("mxb.xml", FileMode.Create))
            {
                SoapFormatter formatter = new SoapFormatter();
                formatter.Serialize(st, objectgrap);
                st.Position = 0;
                objectgrap = null;
                var objectgrap1 = ((string[])formatter.Deserialize(st)).ToList<string>();
                objectgrap1.ForEach(x => Display(0, x));
            }


        }
        private static void Display(int indent, string Format, params object[] obj)
        {
            Console.Write(new string(' ', indent * 2));
            Console.WriteLine(Format, obj);
        }
    }

  

       利用BinaryFormatter.Serialize配合流进行对象图的写入.

       利用BinaryFormatter.DeSerialize进行对象图的还原

       流对象st.Postion如果没设置会报错.

2, 利用序列化创建对象的深拷贝.

 private static object DeepClone(object ori)
        {
            using(MemoryStream ms=new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Context = new StreamingContext(StreamingContextStates.Clone);
                bf.Serialize(ms, ori);
                ms.Position = 0;
                return bf.Deserialize(ms);
            }
        }

   //注意Context中的一个用法,表明这是一个流的一个克隆过程,告诉其他线程该如何处理原对象.

3,利用序列化保存和恢复程序的状态.

 public static void CallSerilalMultiple()
        {
            List<Customer> s_customers = new List<Customer>() { new Customer("abc"),};
            List<order> s_orders = new List<order>() { new order("abc"), };
            using(var fs=new FileStream("mxb.dat", FileMode.OpenOrCreate))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, s_customers);
                bf.Serialize(fs,s_orders);
                s_customers = null;
                s_orders = null;
                GC.Collect();
            }
            using (var fs = new FileStream("mxb.dat", FileMode.OpenOrCreate))
            {
                BinaryFormatter bf = new BinaryFormatter();
                s_customers = (List<Customer>)(bf.Deserialize(fs));
                s_orders = (List<order>)(bf.Deserialize(fs));
            }
            s_customers.ForEach(x => Display(0, x.name));
            s_orders.ForEach(x => Display(0, x.name));
        }
//result

Customerabc ;成功的反序列化原来的对象.
orderabc;成功反序列化原来的对象.

4,让对象可序列化  定制特性SerializableAttribute

只能用于 class,struct,枚举类型和委托类型(后两者总是可序列化).

Serializable特性不被派生类继承,

5,控制序列化

序列化应用于类型时,所有的实列字段都会被序列化.(类的对象),使用NonSerialized,这样,某个字段就不会被序列化.当反序列化的时候,该字段自动清0.

类可设定四个方法进行控制:

  •          private void OnSerializing(StreamContext context)---序列化之前[OnSerializing]
  •          private  void  OnSerialized(streamContext context)---序列化完成后[OnSerialized]
  •          private void  OnDeSerialized(streamContext context)---反序列化之前[OnDeSerializing]
  •          private void  OnDeSerialized(stream Context context)---反序列化之后[OnDeSerialized]

序列化一组对象前,先调用标记OnSerializing特性的所有方法.接着序列化所有字段,接着调用标记OnSerialized特性的所有方法.

反序列化前,先调用OnDeserializing特性的所有方法,然后反序列化所有的对象字段,然后调用标记了OnDeserialized方法.

运行OnDeserialized方法前,会进行由内而外的反序执行(先执行对象指向对象的方法,最后才是对象的方法).

6,格式化器序列化类型实列的过程

          1,使用FormatterServices.GetSerializableMembers,获取(public,private)的可序列化字段

一个MemberInfo[] 数组

          2,调用FormatterServices.GetObjectData(obj,memberinfos)来获取各个字段的data,一个object[]数组,和上面对应.

 public static void CallHowSerialize()
        {
            Customer ct = new Customer("nameadef");
            //1,通过该函数获得类的public和private的字段.
             MemberInfo[] mis= FormatterServices.GetSerializableMembers(typeof(Customer));//可以获取隐藏的属性字段.可获取私有字段.
            
            Array.ForEach<MemberInfo>(mis, x => Display(0,"{0}", x.Name));
            //获取字段的值...
            Display(0, "");
            object[] objs = FormatterServices.GetObjectData(ct, mis);
            Array.ForEach<object>(objs, x => Display(0, "{0}", x.ToString()));
        }

        3,将程序集标识和类型完整名称写入流中

        4,遍历两个数组的元素,将名称和值写入流中

7,反序列化实列的流程

             1,格式化器从流中读取程序集标识和完整的类名称,如果程序集未加载,就试图加载程序集.如果已经加载,就调用函数

               FormatterServices.GetTypeFromAssembly(assembly,string name)获得需要反序列化的对象的类型.

             2,格式化器调用FormatterServices的静态方法

                public static object GetUninitializedObject(Type type)为对象分配内存,但是不为对象调用构造器.然而,所有的字节都

              被初始化为null,或0;

             3,格式化器现在构造,并初始化一个MemberInfo数组,获得MemberInfo[]数组,表示需要反序列化的字段

             4,格式化器根据流中包含的字段值反序列化为一个object[]数组.

             5,将新分配的对象,MemberInfo数组以及Object数组的引用传递给FormatterServices的静态方法

public static object PopulateObjectMembers(
object obj,
MemberInfo[] mis,
object[] datas);

举列:----

 public static void CallHowSerialize()
        {
            Customer ct = new Customer("nameadef");
            //1,通过该函数获得类的public和private的字段.
             MemberInfo[] mis= FormatterServices.GetSerializableMembers(typeof(Customer));//可以获取隐藏的属性字段.可获取私有字段.
            //无法获取隐藏的属性字段.
            Display(0, "Filds to be Serialized:");
            Array.ForEach<MemberInfo>(mis, x => Display(1,"{0}", x.Name));
            //获取字段的值...
            Display(0, "Filds Data to be Serialized:");
            object[] objs = FormatterServices.GetObjectData(ct, mis);
            Array.ForEach<object>(objs, x => Display(1, "{0}", x.ToString()));
            //反序列化对象
            Customer dct = null;
            //获得需要反序列化对象的类型:
            Type t = FormatterServices.GetTypeFromAssembly(Assembly.GetEntryAssembly(), typeof(Customer).FullName);
            //创建一个初始化但未调用构造器的类对象
            dct = (Customer)FormatterServices.GetUninitializedObject(t);
            Display(0, "\n Before Deserialized FieldsData");
            Display(1,"name is {0}",dct.name??"None");
            dct =(Customer) FormatterServices.PopulateObjectMembers(dct, mis, objs);
            Display(0, "\n After Deserialized FieldsData");
            Display(0, "name is {0}", dct.name);
        }

Filds to be Serialized:
   name
   t
   <Props>k__BackingField
Filds Data to be Serialized:
   Customernameadef
   0
   0

Before Deserialized FieldsData
   name is None

After Deserialized FieldsData
name is Customernameadef

1,反序列化过程不调用构造器

2,通过上面函数可以设定私有字段.

8,控制序列化和反序列化的数据----ISerializable接口:

void GetObjectData(SerializationInfo info,StreamingContext context)----一旦某个类实现了它,其派生类也必须实现.(所以,实现了该接口的类最好是密封的sealed).

    如果有该接口,那么在序列化的时候,开始使用info.add添加(key,可序列化对象).然后序列化SerializationInfo对象,并序列化其中引用的所有序列化对象.

    在反序列化的时候,就反序列化SerializationInfo对象,然后调用反序列化构造器,将这个参数和StreamingContext对象传递给反序列化构造器.

    当使用GetValue对象获得的对象和你视图获取的对象不符合,则将调用对象的IFormatterConverter对象,将 GetValue取得的对象进行转换

 s2 = (SerializeTwo)info.GetValue("s2", typeof(object));//后一个是获得对象要转换的类型.

    1,首先创建一个类 SerializeOne

               首先该类有3个字段.

               该类有两个构造器

               该类有一个反序列化构造器

               该类的序列化函数将字段加入info

              该类的反序列化构造器将信息读出并显示

             

internal  class SerializedOne:ISerializable,IDeserializationCallback
    {
        private string m_name;
        private int m_int;
        private List<string> list=new List<string>();


        public SerializedOne():this("initial",default(int),null)
        {

        }
        public SerializedOne(string name,int int1,params string[] strs)
        {
            m_name = name;
            m_int = int1;
            if(strs!=null)list.AddRange(strs);

        }

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("List", list);
            info.AddValue("m_name", m_name);
            info.AddValue("m_int", m_int);


        }

        public void OnDeserialization(object sender)
        {
            Console.WriteLine("DeSerialized!");
        }
        protected SerializedOne(SerializationInfo  info,StreamingContext context)//反序列化构造器,进行反序列化一个新的未构造对象后,进行运行;
        {
            list =(List<string>) info.GetValue("List",typeof(object));
            m_int = (int)info.GetValue("m_int", typeof(int));
            m_name = (string)info.GetValue("m_name", typeof(string));

            Console.WriteLine("DeSerialized Constructor");
            foreach(var enter in info)
            {
                Console.WriteLine(enter.Name+" : "+enter.Value);
            }
        }
        public override string ToString()
        {
            string str=string.Format("\nm_name={0}:m_int={1}", m_name, m_int);
            int index = 0;
            list.ForEach(x => str = str + string.Format("\nItem {0} = {1} ", index++, x));
            return str;
        }
        public virtual void Display() { Console.WriteLine(this.ToString()); }
    }

        2,创建一个类2继承自类1..(类2同时继承了类1的所有字段)

             该类重写了类1的几个方法

internal class SerializeTwo:SerializedOne,ISerializable
    {
        public  string name;
        public SerializeTwo(string name):base(name,100,"abc","efg") { this.name = name; }
        private SerializeTwo(SerializationInfo info, StreamingContext context):base(info,context)//反序列化构造器,进行反序列化一个新的未构造对象后,进行运行;
        {
            name = (string)info.GetValue("name", typeof(string));
        }

        public override  void  GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("name", this.name);

        }
        public override string ToString()
        {
            return base.ToString() + string.Format("\nSerializedTwo's name ={0}", this.name);
        }
        public override void Display()
        {

            Console.WriteLine(ToString());
        }
    }

        

          3,进行测试:

 public static void CallISerializedTwo()
        {
            Console.WriteLine("Show Fileds of SerializeTwo [[[[[:--------------");
                MemberInfo[] mis = FormatterServices.GetSerializableMembers(typeof(SerializeTwo));//可以获取隐藏的属性字段.可获取私有字段.
            Array.ForEach<MemberInfo>(mis, x => Display(1, "{0}", x.Name));

            Console.WriteLine("Show Fileds of SerializeTwo ]]]]:--------------");
            SerializeTwo so = new SerializeTwo("mxb");
            so.Display();
            using (var fs = new FileStream("mxb.dat", FileMode.OpenOrCreate))
            {
                SerializedGJ.Serialize(fs, new BinaryFormatter(), so);
            }
            so = null;

            using (var fs = new FileStream("mxb.dat", FileMode.OpenOrCreate))
            {
                so = (SerializeTwo)SerializedGJ.DeSerialize(fs, new BinaryFormatter());
                so.Display();
            }
        }

Show Fileds of SerializeTwo [[[[[:--------------
   name
   SerializedOne+m_name
   SerializedOne+m_int
   SerializedOne+list
Show Fileds of SerializeTwo ]]]]:--------------

m_name=mxb:m_int=100
Item 0 = abc
Item 1 = efg
SerializedTwo's name =mxb
DeSerialized Constructor
List : System.Collections.Generic.List`1[System.String]
m_name : mxb
m_int : 100
name : mxb
DeSerialized!

m_name=mxb:m_int=100
Item 0 = abc
Item 1 = efg
SerializedTwo's name =mxb

结果:   1,表明派生类继承了基类的字段

          2,当未序列化的时候,各个字段的值

          3,将so引用清0,然后进行反序列化

          4,显示了info类的Key,value内容,

          5,显示类2的所有字段的值.

9,利用如何序列化一个没有被标记为序列化的类

[Serializable]
    internal sealed class NoSerializableToSerialized:ISerializable //我写的一个可以包装未设置序列化类的类.
    {
        private object m_obj;
        private const BindingFlags c_bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;

        public object Obj { get { return m_obj; } }
        public NoSerializableToSerialized(object obj) { m_obj = obj; }

        private NoSerializableToSerialized(SerializationInfo info, StreamingContext context)
        {
            Type t = (Type)info.GetValue("TypeOfObject", typeof(Type));//反序列化m_obj的对象类型.
            m_obj = Activator.CreateInstance(t);//创建类型实列.
            FieldInfo[] mis = null;

            if (m_obj.GetType().IsDefined(typeof(SerializableAttribute)))//如果是序列化类调用....
            {
                mis = (FieldInfo[])FormatterServices.GetSerializableMembers(m_obj.GetType());

            }
            else//非序列化类调用....
            {
                mis = m_obj.GetType().GetTypeInfo().GetFields(c_bf);

            }




            for (int i = 0; i < mis.Length; i++)
            {
                var mi = mis[i];

                if (!mi.FieldType.GetTypeInfo().IsDefined(typeof(SerializableAttribute)))//非序列化类,迭代解析.
                {

                    var objss = (NoSerializableToSerialized)info.GetValue(mi.Name + i, typeof(NoSerializableToSerialized));
                    mi.SetValue(m_obj, objss.Obj);
                }
                else//否则直接获得对象.
                {
                    mi.SetValue(m_obj, info.GetValue(mi.Name + i, mi.FieldType));
                }

            }



        }
        //自定义序列化函数
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {

            info.AddValue("TypeOfObject", m_obj.GetType(), typeof(Type));//将对象类型序列化
            FieldInfo[] mis = null;
            object[] objs = null;
            if (m_obj.GetType().IsDefined(typeof(SerializableAttribute)))//如果是序列化类型,调用GetSerializableMembers
            {
                mis =(FieldInfo[])FormatterServices.GetSerializableMembers(m_obj.GetType());
                objs = FormatterServices.GetObjectData(m_obj, mis);
                Console.WriteLine("\n defined serial");
            }
            else//如果是非序列化,调用GetFields.
            {
                mis = m_obj.GetType().GetTypeInfo().GetFields(c_bf);
                objs = FormatterServices.GetObjectData(m_obj, mis);
            }

            for (int i = 0; i < mis.Length; i++)
            {
                var mi = mis[i];
                var obj = objs[i];
                //如果Field是非序列化对象,则进行包装,再序列化.否则直接加入Info
                if (!mi.FieldType.GetTypeInfo().IsDefined(typeof(SerializableAttribute)))
                {
                    info.AddValue(mi.Name + i, new NoSerializableToSerialized(obj));
                }
                else
                {
                    info.AddValue(mi.Name + i, obj);
                }

            }


        }

    }

10,单实列对象序列化


public sealed class Singleton : ISerializable
    {
        private static readonly Singleton s_theOneObject = new Singleton();
        public string Name = "Jeff";
        public DateTime Date=DateTime.Now;
        private Singleton() { }

        public static Singleton GetSingleton() { return s_theOneObject; }

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.SetType(typeof(SingletionSerializationHelper));
        }
        private Singleton(SerializationInfo info, StreamingContext context)//该函数未运行.
        {
            Console.WriteLine("Deserialization Singletion");
        }
        [Serializable]
        private sealed class SingletionSerializationHelper : IObjectReference
        {
            public object GetRealObject(StreamingContext context)
            {
                return Singleton.GetSingleton();
            }
        }
    }

  1,使用SetType表示在序列化的时候将序列化一个SingletionSerializationHelper对象,----将该对象的程序集和类型信息写入序列化中

  2,在反序列化的时候,格式化器知道这是一个由类型转换来的对象.所以它首先反序列化成一个SingletionSerializationHelper对象.

  注意:该对象必须实现接口IObjectReference,然后调用该对象的GetRealObject对象---让它返回一个所需要的对象.(这个方法主要用于对单实列类进行保存.


11,序列化代理:(利用代理可以重写和覆盖,将类型反馈为一个不同的版本)

序列化代理必须事件ISerializationSurrogate接口

该接口实现了2个函数:

GetObjectData(Object, SerializationInfo, StreamingContext)
//用序列化对象所需的数据填充所提供的 SerializationInfo。
SetObjectData(Object, SerializationInfo, StreamingContext, ISurrogateSelector)
反序列化时,利用其将SerializationInfo中
  •           当某个类型 和 序列化代理关联的时候,那么,序列化这个对象,就调用了GetObjectData方法,(ISerializable)中的方法.并且

第一个参数为,该类型的实列,第二个参数为格式化器提供的Info.

          当反序列化的时候,首先使用FormatterServices.GetUninitializedObject()建立一个关联类型的未初始化的实列.该实列的所有的Field是NUll,或者0;

          然后这个参数作为第一个参数传给SetObjectData,这个参数可用,可不用.

  •     首先创建一个需要代理的类(测试用,非实现Serializable)
  •  public class TestForSurrogate//一个测试类,当序列化的时候,不管序列化时间,反序列化的时候,更新其时间
        {
            public DateTime dt = DateTime.Now;
            public String Name;
            public TestForSurrogate(string name)
            {
                Name = name;
            }
        }

             

public sealed class MySurrogateForSurrogateTest : ISerializationSurrogate
    {
        public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
        {
            TestForSurrogate Myboj = (TestForSurrogate)obj;
            Myboj.dt = DateTime.Now;
            Console.WriteLine(Myboj.Name+Myboj.dt.ToString());
            info.AddValue("Name", Myboj.Name);
            info.AddValue("time", Myboj.dt);
        }

        public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
        {
            TestForSurrogate Myboj = (TestForSurrogate)obj;
            Myboj.dt = (DateTime)info.GetValue("time",typeof(object));
            Myboj.Name = (string)info.GetValue("Name", typeof(object));
            Console.WriteLine(Myboj.Name + Myboj.dt.ToString());
            return Myboj;
        }
    }

然后创建一个surrogateSelector对象,并且进行绑定

 SurrogateSelector selector = new SurrogateSelector();
                selector.AddSurrogate(typeof(TestForSurrogate), formatter.Context, new MySurrogateForSurrogateTest());

然后将其赋值给,Formmater的SurrogateSelecotor属性

 formatter.SurrogateSelector = selector;
  • 然后就能工作了,当序列化       一个TestForSurrogate对象,就会调用MySurrogateForSurrogateTest.GetObjectData
  •              当反序列化时候,就会调用MySurrogateForSurrogateTest.SetObjectData

注意,Selector实现了接口ISurrogateSelector接口:

ChainSelector 将Selector链接起来

GetNextSelector 获得下一个Selector

GetSurrgate,在Selector链中查找.

               相当于KeyValue<type,Surrogate)----组成了一个 Selector,

               Selector.Chain(Selector1)将Selector1加入到Selector链中.


   12,反序列化的时候重写程序集/类型-----------SerializationBinder对象的使用.

        1,自己实现一个SerializationBinder的派生类.

 public class MySerializationBinder : SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            Console.WriteLine("BInderToType...");
            Console.WriteLine("\n" + assemblyName);
            Console.WriteLine("\n" + typeName);
            //return Type.GetType(typeName +","+ assemblyName);//加,号,因为否则生成的typename是不完整的.
            return typeof(TestForSurrogate1);
        }


    }

    2,其赋值给Formmater.Binder

formatter.Binder = new MySerializationBinder();

   3,实现绑定类型类,将---类TestForSurrogate返回给类TestForSurrogate1


 public sealed class TestForSurrogate1:ISerializable//一个测试类,当序列化的时候,不管序列化时间,反序列化的时候,更新其时间
    {
        public DateTime dt = DateTime.Now;
        public String Name;
        public TestForSurrogate1(string name)
        {
            Name = name;
        }
        private TestForSurrogate1(SerializationInfo info, StreamingContext context)
        {
            Console.WriteLine("test1 Deserialized..");
            try
            {
                info.GetValue("Test1", typeof(TestForSurrogate1));
            }
            catch(Exception)
            {
                Console.WriteLine("it's From Surrogate v1.0");
                this.Name = (string)info.GetValue("Name", typeof(object));
                this.dt = DateTime.Now;
            }

        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Test1", this);
        }
    }

   4,测试如下代码

public static void Call1()
        {
            using (var st = new FileStream("mxb.xml", FileMode.Create))
            {
                SoapFormatter formatter = new SoapFormatter();
                SurrogateSelector selector = new SurrogateSelector();
                selector.AddSurrogate(typeof(TestForSurrogate), formatter.Context, new MySurrogateForSurrogateTest());
                formatter.SurrogateSelector = selector;
                formatter.Binder = new MySerializationBinder();
                formatter.Serialize(st, new TestForSurrogate("mxb"));
                //必须,表明要格式化的位置?
                st.Position = 0;
                var objectgrap1 = formatter.Deserialize(st);
                Console.WriteLine(objectgrap1.GetType().ToString());
                Console.WriteLine(((TestForSurrogate1)objectgrap1).Name);

            }
        }
    }

   其结果如下:

mxb2020/2/19 21:32:55
BInderToType...

ClrFromCSharp_2_2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=11fccde6e91ad1e9

ClrFromCSharp_2_2.LearnSerialize.TestForSurrogate
test1 Deserialized..
it's From Surrogate v1.0
ClrFromCSharp_2_2.LearnSerialize.TestForSurrogate1
mxb

xml文件内容如下

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:Singleton_x002B_SingletionSerializationHelper id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/ClrFromCSharp_2_2.LearnSerialize/ClrFromCSharp_2_2%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D11fccde6e91ad1e9">
<Name id="ref-3">Jeff</Name>
</a1:Singleton_x002B_SingletionSerializationHelper>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

表明对象序列化的绑定器和绑定的类别.  ------------就是创建了一个单实列的SingletionSerializationHelper.

当反序列化的时候,格式化器通过selector知道这个Selector绑定的类别

然后创建该类别非初始化实列

然后传递给SetObjectData的第一个参数.执行这个函数.

--------------

当由Binder之后,对象在反序列化的时候,首先

  •          执行Binder的BinderToType函数,然后返回了一个Type.
  •          然后,如果该类型有ISerialize接口,调用反序列化构造器.
  •          否则,调用默认反序列化过程,见上面.

上面的列子很有意思

由于Selector和Surrogate的缘故,首先当序列化一个TestForSurrogate对象的时候,会先调用代理的序列化函数.

但是,由于binder的作用,再返回的时候,因为,创建了一个TestForSurrogate1对象,会调用TestForSurrogate1,的反序列化构造器.

猜你喜欢

转载自www.cnblogs.com/frogkiller/p/12336879.html