C#对字典容器Dictionary<TKey, TValue>内容进行XML序列化或反序列化报错解决方法

一、问题描述

在使用C#对字典容器Dictionary<TKey, TValue>内容进行XML序列化报错【System.Exception:"不支持类型 System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],因为它实现 IDictionary。"】如下所示:

或反序列化操作时会报如下错误【System.Exception:"不支持类型 System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],因为它实现 IDictionary。"】如下图所示

二、问题分析

通过异常信息可以看到是由于XML序列化或反序列化程序导致报错,且该错误是由于IDictionary导致,通过反编译查看【System.Xml.Serialization.TypeScope】内容可以发现代码直接对IDictionary类型直接做返回异常处理,不让序列化或反序列化。

三、解决方法

1、创建一个新的类【DictionaryEx】,继承Dictionary<TKey, TValue>类和IXmlSerializable接口:

cs 复制代码
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Kernal
{
    #region 可序列化字典类 + public class DictionaryEx<TKey, TValue>
    /// <summary>
    /// 可序列化字典类
    /// </summary>
    /// <typeparam name="TKey">键泛型</typeparam>
    /// <typeparam name="TValue">值泛型</typeparam>
    [System.Serializable]
    public class DictionaryEx<TKey, TValue>
      : Dictionary<TKey, TValue>, IXmlSerializable
    {
        #region 构造函数

        #region 默认构造函数 + public DictionaryEx()
        /// <summary>
        /// 默认构造函数
        /// </summary>
        public DictionaryEx()
            : base()
        {

        }
        #endregion

        #region 构造函数 + public DictionaryEx(int capacity)
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="capacity">可包含的初始元素数</param>
        public DictionaryEx(int capacity)
            : base(capacity)
        {

        }
        #endregion

        #region 构造函数 + public DictionaryEx(IEqualityComparer<TKey> comparer)
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="comparer">比较键时要使用的 比较器 实现,或者为 null,以便为键类型使用默认的 比较器</param>
        public DictionaryEx(IEqualityComparer<TKey> comparer)
            : base(comparer)
        {

        }
        #endregion

        #region 构造函数 + public DictionaryEx(IDictionary<TKey, TValue> dictionary)
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dictionary">初始数据</param>
        public DictionaryEx(IDictionary<TKey, TValue> dictionary)
            : base(dictionary)
        {

        }
        #endregion

        #region 构造函数 + public DictionaryEx(int capacity, IEqualityComparer<TKey> comparer)
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="capacity">可包含的初始元素数</param>
        /// <param name="comparer">比较键时要使用的 比较器 实现,或者为 null,以便为键类型使用默认的 比较器</param>
        public DictionaryEx(int capacity, IEqualityComparer<TKey> comparer)
            : base(capacity, comparer)
        {

        }
        #endregion

        #region 构造函数 + public DictionaryEx(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dictionary">初始数据</param>
        /// <param name="comparer">比较键时要使用的 比较器 实现,或者为 null,以便为键类型使用默认的 比较器</param>
        public DictionaryEx(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
            : base(dictionary, comparer)
        {

        }
        #endregion

        #endregion

        #region 取得概要 + public XmlSchema GetSchema()
        /// <summary>
        /// 取得概要
        /// 注:根据MSDN的文档,此方法为保留方法,一定返回 null。
        /// </summary>
        /// <returns>Xml概要</returns>
        public XmlSchema GetSchema()
        {
            return null;
        }
        #endregion

        #region 从 XML 对象中反序列化生成本对象 + public void ReadXml(XmlReader reader)
        /// <summary>  
        /// 从 XML 对象中反序列化生成本对象
        /// </summary>  
        /// <param name="reader">包含反序列化对象的 XmlReader 流</param>  
        public void ReadXml(XmlReader reader)
        {
            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
            bool wasEmpty = reader.IsEmptyElement;
            reader.Read();
            if (wasEmpty) return;

            while (reader.NodeType != XmlNodeType.EndElement)
            {
                reader.ReadStartElement("Item");
                reader.ReadStartElement("Key");
                TKey key = (TKey)keySerializer.Deserialize(reader);
                reader.ReadEndElement();
                reader.ReadStartElement("Value");
                TValue value = (TValue)valueSerializer.Deserialize(reader);
                reader.ReadEndElement();
                this.Add(key, value);
                reader.ReadEndElement();
                reader.MoveToContent();
            }

            reader.ReadEndElement();
        }
        #endregion

        #region 将本对象序列化为 XML 对象 + public void WriteXml(XmlWriter writer)
        /// <summary>  
        /// 将本对象序列化为 XML 对象
        /// </summary>  
        /// <param name="writer">待写入的 XmlWriter 对象</param>  
        public void WriteXml(XmlWriter writer)
        {
            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
            foreach (TKey key in this.Keys)
            {
                writer.WriteStartElement("Item");
                writer.WriteStartElement("Key");
                keySerializer.Serialize(writer, key);
                writer.WriteEndElement();
                writer.WriteStartElement("Value");
                TValue value = this[key];
                valueSerializer.Serialize(writer, value);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
        #endregion
    }
    #endregion
}

2、将原来使用Dictionary的类替换为DictionaryEx类

cs 复制代码
        /// <summary>
        /// 保存语言信息
        /// </summary>
        private bool SaveFileExpandNameList(DictionaryEx<string,string> languageInfoDic, string languageFilePathAndName)
        {
            bool success = false;
            if (languageInfoDic != null && languageInfoDic.Count >= 0)
            {
                //将对象序列化为xml字符串
                string strXml = XmlHelper.ObjectToXml2(languageInfoDic);
                if (!string.IsNullOrEmpty(strXml))
                {
                    //先清空文件
                    FileOPC.Clear(languageFilePathAndName);
                    //保存Json字符串文件(覆盖写入)
                    success = FileOPC.OverWrite(languageFilePathAndName, strXml);
                }
            }
            return success;
        }


        /// <summary>
        /// 获取语言信息
        /// </summary>
        /// <returns>返回语言信息字典</returns>
        private DictionaryEx<string, string> GetLanguageInfo(string languageFilePathAndName)
        {
            if (string.IsNullOrEmpty(languageFilePathAndName)) return null;

            DictionaryEx<string, string> languageInfoDic = new DictionaryEx<string, string>();

            //读取xml文件字符串
            string strXml = FileOPC.Read(languageFilePathAndName);

            //读取xml文件并序列化为对象
            languageInfoDic = XmlHelper.XmlToObject2<DictionaryEx<string, string>>(strXml);

            return languageInfoDic;
        }

3、序列化DictionaryEx<TKey, TValue>容器内容的XML内容如下所示:

相关推荐
令狐少侠20115 小时前
maven settings.xml文件的各个模块、含义以及它们之间的联系
xml·maven
l1t9 小时前
张泽鹏先生手搓的纯ANSI处理UTF-8与美团龙猫调用expat库读取Excel xml对比测试
xml·人工智能·excel·utf8·expat
charlie11451419113 小时前
Android开发——初步了解AndroidManifest.xml
android·xml·开发语言·学习·安卓·安全架构
热烈勒温18 小时前
Mybatis入门、操作数据、配置xml映射、数据封装
xml·mybatis
微笑伴你而行1 天前
目标检测如何将同时有方形框和旋转框的json/xml标注转为txt格式
xml·目标检测·json
fatiaozhang95272 天前
数码视讯TR100-OTT-G1_国科GK6323_安卓9_广东联通原机修改-TTL烧录包-可救砖
android·xml·电视盒子·刷机固件·机顶盒刷机
l1t2 天前
美团龙猫利用expat库实现的保存xml指定范围数据到csv的C程序
xml·c语言·解析器·expat
l1t3 天前
DuckDB新版rusty_sheet 插件测试
xml·数据库·rust·插件·xlsx·duckdb
l1t3 天前
美团龙猫(longcat.AI)编写的利用二分查找优化Excel的sheet.xml指定范围输出C程序
xml·c语言·excel·解析器
LB21124 天前
MyBatis xml配置文件
xml·java·mybatis