• C# 序列化与反序列化之Binary与Soap无法对泛型List<T>进行序列化的解决方案


    C# 序列化与反序列化之Binary与Soap无法对泛型List<T>进行序列化的解决方案

    新建Console控制台项目项目,然后添加Team和Person 这2个类,如下:

    Team和Person 这2个类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SupremeConsole
    {
        [Serializable]
        public class Team
        {
    
            /// <summary>
            /// 队名
            /// </summary>
            public string TName { get; set; }
    
            /// <summary>
            /// 选手
            /// </summary>
            public List<Person> PlayerList = new List<Person>();
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SupremeConsole
    {
        [Serializable]
        public class Person
        {
            /// <summary>
            /// 姓名
            /// </summary>       
            public string Name { get; set; }
    
            /// <summary>
            /// 年龄
            /// </summary>
            public int Age { get; set; }
        }
    }

    使用Binary或者Soap进行序列化,本例演示使用Soap对类型种的泛型字段进行序列化,代码如下:

    using System;
    using System.Data;
    using System.Data.SQLite;
    using System.Diagnostics;
    using System.IO;
    using System.IO.Compression;
    using System.IO.MemoryMappedFiles;
    using System.IO.Pipes;
    using System.Linq;
    using System.Net;
    using System.Security.AccessControl;
    using System.Security.Principal;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Reflection;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Runtime.Serialization;
    
    namespace SupremeConsole
    {
        class Program
        {
            static void Main(string[] args)
            {
               TestSeri();
                Console.ReadLine();
            }
    
     public static void TestSeri() {
                Team team = new Team { TName="123",PlayerList = { new Person { Name="1",Age=1},new Person { Name = "2", Age = 2 } } };
                #region BinarySerialize 必须添可序列化属性,即要序列化的对象必须添加SerializableAttribute属性,[Serializable]
                //string s = SerializeManager.Instance.BinarySerialize<Team>(team);//序列化
                //Console.ForegroundColor = ConsoleColor.Green;
                //Console.WriteLine("测试序列化成功。。。");
                //Console.WriteLine($"测试序列化结果:
    {s}");
    
                //string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "序列化11111.bin");//序列化
                //SerializeManager.Instance.BinarySerialize<Team>(team, path);
    
                //string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "序列化11111.bin");
                //Team test = SerializeManager.Instance.BinaryDeserialize<Team>(path);//反序列化
                //if (test != null)
                //{
                 //   Console.WriteLine($"测试序列化结果:{test.ToString()}");
                //}
                #endregion
    
                #region SoapSerialize 必须添可序列化属性,即要序列化的对象必须添加SerializableAttribute属性,[Serializable]
                string s = SerializeManager.Instance.SoapSerialize<Team>(team);//序列化
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("测试序列化成功。。。");
                Console.WriteLine($"测试序列化结果:
    {s}");
    
                //string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Soap序列化.xml");//序列化
                //SerializeManager.Instance.SoapSerialize<Team>(team, path);
    
    
                //string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Soap序列化.xml");
                //Team test = SerializeManager.Instance.SoapDeserialize<Team>(path);//反序列化
                //if (test != null)
                //{
                //    Console.WriteLine($"测试序列化结果:{test.ToString()}");
                //}
                #endregion
            }
            /// <summary>
            /// Binary泛型序列化
            /// </summary>
            /// <typeparam name="T">泛型类型</typeparam>
            /// <param name="t">泛型对象</param>
            /// <returns>泛型对象序列化的字符串</returns>
            public string BinarySerialize<T>(T t) where T : class
            {
                string s = null;
                try
                {
                    using MemoryStream ms = new MemoryStream();
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(ms, t);
                    s = Encoding.UTF8.GetString(ms.ToArray());
                }
                catch (Exception ex)
                {
                    Program.Log.Error($"Binary泛型序列化错误信息:{ex.ToString()}");
                }
                return s;
            }
    
            /// <summary>
            /// Binary泛型序列化
            /// </summary>
            /// <typeparam name="T">泛型类型</typeparam>
            /// <param name="t">泛型对象</param>
            /// <param name="path">保存的路径</param>
            public void BinarySerialize<T>(T t, string path) where T : class
            {
                try
                {
                    //string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.txt");
                    using FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(fs, t);
                }
                catch (Exception ex)
                {
                    Program.Log.Error($"Binary泛型序列化错误信息:{ex.ToString()}");
                }
            }
    
            /// <summary>
            /// Binary泛型的反序列化
            /// </summary>
            /// <typeparam name="T">泛型类型</typeparam>
            /// <param name="path">反序列化的序列化文件路径</param>
            /// <returns>泛型对象</returns>
            public T BinaryDeserialize<T>(string path) where T : class
            {
                T t = null;
                try
                {
                    //string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.txt");
                    using MemoryStream fs = new MemoryStream(File.ReadAllBytes(path));
                    BinaryFormatter bf = new BinaryFormatter();
                    if (bf.Deserialize(fs) is T a)
                    {
                        t = a;
                    }
                }
                catch (Exception ex)
                {
                    Program.Log.Error($"Binary泛型的反序列化错误信息:{ex.ToString()}");
                }
                return t;
            }
    }
    }

    运行程序报错,错误信息是无法对泛型进行序列化,

    第一种解决方式:Soap序列化无法对泛型List<T>进行序列化,解决方法1 :使用[OnSerializing]特性解决泛型List<T>序列化,修改Team为下面代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SupremeConsole
    {
        [Serializable]
        public class Team
        {
            #region 初始定义,使用Soap序列化PlayerList会报错,因为Soap序列化无法对泛型List<T>进行序列化,解决方法如下
            ///// <summary>
            ///// 队名
            ///// </summary>
            //public string TName { get; set; }
    
            ///// <summary>
            ///// 选手
            ///// </summary>
            //public List<Person> PlayerList = new List<Person>(); 
            #endregion
    
            #region Soap序列化无法对泛型List<T>进行序列化,解决方法1 :使用[OnSerializing]特性解决泛型List<T>序列化
            /// <summary>
            /// 队名
            /// </summary>
            public string TName { get; set; }
    
            Person[] _PlayerArr;
    
            /// <summary>
            /// 选手
            /// </summary>
            [NonSerialized] public List<Person> PlayerList = new List<Person>();
    
            [OnSerializing]
            public void SetPlayer(StreamingContext sc)
            {
                _PlayerArr = PlayerList.ToArray();
            }
    
            [OnDeserialized]
            public void SetPlayered(StreamingContext sc)
            {
                _PlayerArr = null;
            }
    
            [OnDeserializing]
            public void GetPlayer(StreamingContext sc)
            {
                PlayerList = new List<Person>(_PlayerArr);
            }
    
            #endregion
        }
    }

    在运行,可以序列化,但是反序列化的时候报错,集合为空错误,那么我们使用第二中解决方法,即实现ISerializable接口,

    ISerializable接口中有GetObjectData(SerializationInfo info, StreamingContext context),序列化的时候会调用该方法,可以操作参数SerializationInfo ,SerializationInfo 是一个a name-value dictionary,

    反序列化的时候,可以使用构造函数,构造函数的参数和GetObjectData的参数一样,即构造函数(SerializationInfo info, StreamingContext context)。

    第二种解决方式:实现ISerializable接口对泛型List<T>进行序列化,修改Team为下面代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SupremeConsole
    {    
        [Serializable]
        public class Team : ISerializable
        {
            /// <summary>
            /// 队名
            /// </summary>
            public string TName { get; set; }
    
            /// <summary>
            /// 选手
            /// </summary>
            public List<Person> PlayerList = new List<Person>();
    
            /// <summary>
            /// 序列化的时候会自动调用,使用virtual标记,示方便继承自类的使用
            /// </summary>
            /// <param name="info"></param>
            /// <param name="context"></param>
            public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                info.AddValue("TName", TName);
                info.AddValue("PlayerList", PlayerList);
            }
    
            public Team()
            {
    
            }
    
            /// <summary>
            /// 反序了列化的时候自动调用,使用protected标记,示方便继承自类的使用
            /// </summary>
            protected Team(SerializationInfo info, StreamingContext context)
            {
                TName = info.GetString("TName");
                PlayerList = (List<Person>)info.GetValue("PlayerList",typeof(List<Person>));
            }
        }
    }

    再运行程序,可以看到序列化和反序列化都可以了。

    其实,Binary与Soap无法对泛型List<T>进行序列化的解决方案,无非就是使用[OnSerializing]特性实现ISerializable接口,

  • 相关阅读:
    剑指 Offer 31. 栈的压入、弹出序列
    剑指 Offer 33. 二叉搜索树的后序遍历序列
    剑指 Offer 36. 二叉搜索树与双向链表
    tarjan 强连通分量
    剑#指 Offer 34. 二叉树中和为某一值的路径
    剑指 Offer 32 III. 从上到下打印二叉树 III
    Tarjan C++版
    剑指 Offer 35. 复杂链表的复制
    tarjan2
    Vue:解决“此图片来自微信公众平台 未经允许不可引用”问题的方法
  • 原文地址:https://www.cnblogs.com/1175429393wljblog/p/12034056.html
Copyright © 2020-2023  润新知