【C#编程最佳实践 四】XML配置文件编写与读取实践

通过项目获取的新技能,之后写xml配置应该没什么问题,当然xml文件的使用形式多种多样,之后在持续更新。

配置文件编写实践

配置文件一般用xml来写,具体关于xml文件的特性见以下这篇引用的博客,很详细了。

xml文件的使用http://blog.csdn.net/wuya_meiya/article/details/50989600

这里我想说一下我学到的设计

xml文件编写

<?xml version="1.0" encoding="utf-8" ?> <CheckMetaDataConfig majorVersion="1" minorVersion="208" //根节点 <DataBases> <DataBase Name="User"> <TableConfigs> <TableConfig Name="dbo.userconfig" ConditionCode="ID,Lable,Name"> //ConditonCode为配置的组合特征,之后需要取出来切割并调用 <Fields> <Field Name="ID" Method="Mapping" Field> //method为我们的比较规则 <Field Name="Lable" Method="Equal"></Field> <Field Name="Name" Method="TenanatReplace"></Field> <Field Name="Application" Method="Equal"></Field> </Fields> </TableConfig> </TableConfigs> </DataBase> </DataBases> </CheckMetaDataConfig>

以上的结构为,一系列的库,一系列的表,一系列的字段,每一级都可以有很多个,每个又可以有自己的属性。为了对应xml,我们需要解析,还要考虑到我们会通过库来调用表,通过表来调用字段

解析xml文件的类的编写

using User.Configuration;
using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace User
{
    //=============================对应根节点的类==========================================

    #region 对应根节点的类

    /// <summary>
    /// 类:对应根节点的类
    /// </summary>
    [XmlRoot("CheckMetaDataConfig")]
    public class CheckMetaDataConfig : BaseConfig<CheckMetaDataConfig>
    {
        private static readonly object LockThis = new object(); //获取锁对象

        //=============================================属性部分====================================
        [XmlArray("DataBases")]
        [XmlArrayItem("DataBase")]
        public DataBase[] DataBases { get; set; }

        //=============================================字段部分====================================
        private Dictionary<string, DataBase> _databasedic; //设置字段的字典类

        //=============================================方法部分====================================

        /// <summary>
        /// 公有方法:获取指定名称数据库的xml实例
        /// </summary>
        /// <param name="dataBaseName"></param>
        /// <returns></returns>
        public DataBase FindDatabase(string dataBaseName)
        {
            dataBaseName = dataBaseName.ToLower();
            if (_databasedic == null)
            {
                InitDatabaseDic();
            }

            return _databasedic != null && _databasedic.ContainsKey(dataBaseName) ? _databasedic[dataBaseName] : null;
        }

        /// <summary>
        /// 私有方法:初始化数据库
        /// </summary>
        private void InitDatabaseDic()
        {
            lock (LockThis)
            {
                if (_databasedic == null) //如果字典为null,则初始化字典类
                {
                    var dic = new Dictionary<String, DataBase>(); //新建一个字典类
                    foreach (var app in Instance.DataBases) //遍历该数据库
                    {
                        app.Name = app.Name.ToLower(); //将数据库名全部转为大写
                        if (string.IsNullOrEmpty(app.Name)) continue; //如果该配置文件里的数据库名字存在,则中止,进入下一个
                        if (!dic.ContainsKey(app.Name)) //如果字段名字典里不包括该实例里的数据库的名字,添加进去
                        {
                            dic.Add(app.Name, app); //把数据库名字和数据库实例以字典对的形式添加进去
                        }
                    }
                    _databasedic = dic; //把处理好的dic赋给字典,全新的字典诞生
                }
            }
        }
    }
}

#endregion 对应根节点的类

//=============================对应数据库节点的类==========================================

#region 对应数据库节点的类

/// <summary>
/// 类:数据库节点类
/// </summary>
public class DataBase
{
    private static readonly object LockThis = new object(); //获取锁对象

    //=============================================属性部分====================================
    [XmlAttribute("Name")]
    public string Name { get; set; }

    [XmlArray("TableConfigs")]
    [XmlArrayItem("TableConfig")]
    public TableConfig[] TableConfigs { get; set; }

    //=============================================字段部分====================================
    private Dictionary<string, TableConfig> _tableDic;

    //=============================================方法部分====================================
    /// <summary>
    ///公有方法: 获取指定名称的数据表
    /// </summary>
    /// <param name="tableName"></param>
    /// <returns></returns>
    public TableConfig FindTable(string tableName)
    {
        tableName = tableName.ToLower();
        if (_tableDic == null)
        {
            InitTableDic();
        }
        return _tableDic != null && _tableDic.ContainsKey(tableName) ? _tableDic[tableName] : null;
    }

    /// <summary>
    /// 私有方法:初始化数据表的信息
    /// </summary>
    private void InitTableDic()
    {
        lock (LockThis)
        {
            if (_tableDic == null) //如果字典为null,则初始化字典类
            {
                var dic = new Dictionary<String, TableConfig>(); //新建一个字典类
                foreach (var app in TableConfigs) //遍历该表集合
                {
                    app.Name = app.Name.ToLower(); //将数据表名全部转为大写
                    if (string.IsNullOrEmpty(app.Name)) continue; //如果该配置文件里的数据库名字存在,则中止,进入下一个
                    if (!dic.ContainsKey(app.Name)) //如果字段名字典里不包括该实例里的数据表的名字,添加进去
                    {
                        dic.Add(app.Name, app); //把数据表名字和数据表实例以字典对的形式添加进去
                    }
                }
                _tableDic = dic; //把处理好的dic赋给字典,全新的字典诞生
            }
        }
    }
}

#endregion 对应数据库节点的类

//=============================对应数据表节点的类==========================================

#region 对应数据表节点的类

/// <summary>
/// 类:数据表节点类
/// </summary>
public class TableConfig
{
    private static readonly object LockThis = new object(); //获取锁对象

    //=============================================属性部分====================================
    [XmlAttribute("Name")]
    public string Name { get; set; }

    [XmlAttribute("ConditionCode")]
    public string ConditionCode { get; set; }

    [XmlArray("Fields")]
    [XmlArrayItem("Field")]
    public Field[] Fields { get; set; }

    //=============================================字段部分====================================
    private Dictionary<String, string> _conditionCodDic;

    //=============================================方法部分====================================
    /// <summary>
    /// 公有方法:获取特征码
    /// </summary>
    /// <returns></returns>
    public Dictionary<String, string> GetConditionCodeDic()
    {
        if (_conditionCodDic == null)
        {
            InitConditionCodeDic();
        }
        return _conditionCodDic;
    }

    /// <summary>
    /// 私有方法: 初始化特征码
    /// </summary>
    private void InitConditionCodeDic()
    {
        lock (LockThis)
        {
            if (_conditionCodDic == null) //如果字典为null,则初始化字典类
            {
                var dic = new Dictionary<string, string>(); //新建一个字典类
                var strs = ConditionCode.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                //不保留空元素,获取到特征值字段集合
                foreach (var s in strs)
                {
                    dic.Add(s, null);
                }
                _conditionCodDic = dic; //把处理好的dic赋给字典,全新的字典诞生
            }
        }
    }
}

#endregion 对应数据表节点的类

//=============================对应字段节点的类==========================================

#region 对应字段节点的类

/// <summary>
/// 类: 字段类
/// </summary>
public class Field
{
    //=============================================属性部分====================================
    [XmlAttribute("Name")]
    public string Name { get; set; }

    [XmlAttribute("Method")]
    public string Method { get; set; }
}

#endregion 对应字段节点的类

以上代码类似InitTableDic用到的初始化方式可以大大减少访问次数,如果存在就不需要再次获取

调用xml文件类

var dataDaseConfig = CheckMetaDataConfig.Instance.FindDatabase(MetaDataBaseName);  //获取一个配置文件中数据库节点实例

踩过的坑

1,xml解析类编写的时候,字典类的访问修饰符必须是private:private Dictionary<String, string> _conditionCodDic;
2,xml解析类尽量不要出现子类,要写为同级的
3,注意xml文件名必须和xml解析类必须同名

全部评论

相关推荐

零零幺零零幺:至少再做一个项目,然后猛投小厂,不然有点难
点赞 评论 收藏
分享
03-19 18:27
已编辑
门头沟学院 C++
26学院本太难了,很多公司机筛就给我刷了。机会都难拿到如果是简历存在问题也欢迎拷打————————————————————分割线——————————————————————2026.3.4更新:发完贴之后,时不时投递又收到了不少的笔试/面试邀请。主要是之前投递简历出去之后基本上都是沉默状态,年后好转了不少timeline:2026.01.21&nbsp;文远知行笔试,半年多没刷算法题&nbsp;-&gt;挂&nbsp;(后续HR说春招可以重新安排笔试)2026.2.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;小鹏汇天&nbsp;技术一面,第二周收到结果&nbsp;-&gt;挂2026.2.12&nbsp;&nbsp;&nbsp;大众Cariad代招&nbsp;技术二面&nbsp;-&gt;Offer2026.2.28&nbsp;&nbsp;&nbsp;多益网络技术面试,由于风评太差,一直在犹豫要不要接面试&nbsp;-&gt;推迟-----------分割线-----------2026.3&nbsp;月前的某一天,临时去电网报名了二批计算机岗位的笔试2026.3.6&nbsp;从上家公司实习离职,氛围最好的一家公司,leader&nbsp;说可以帮忙转正,但是流程太长,而且我们部门据说只有一个&nbsp;hc,更想要研究生,我很有可能是会被签外包公司在这里干活,就离职了。2026.3.9&nbsp;入职新公司,大众Cariad&nbsp;以外部公司的身份进组,项目组签了三年,后续三年应该都可以在这里呆,不知道有没有希望原地跳槽。2026.3.10&nbsp;电网考试居然说我通过资格审查了,短信约我去参加资格审查,请假一天,买了&nbsp;12&nbsp;号晚上的机票回成都2026.3.15&nbsp;参加国家电网三新计算机类的笔试2026.3.17&nbsp;电网出成绩了,感觉很低。觉得已经🈚️了2026.3.18&nbsp;收到电网面试通知,通知&nbsp;3.22-3.25&nbsp;这个时间去面试,我的岗位只招&nbsp;1&nbsp;个人。据说面试只有&nbsp;2-3&nbsp;人,不知道能不能成功
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务