c#自定义Attribute模拟JAVA的Annotation实现属性xml的读取

声明

突发奇想的一个处理问题的方法,好不好用不用就仁者见仁智者见智了。

用法

1. 实现自定义Attribute

namespace 秃顶韭菜的命名空间
{
    public class XmlMapping : Attribute
    {
        /// <summary>
        /// xml属性地址
        /// </summary>
        private string xmlAddress = string.Empty;

        /// <summary>
        /// xml中存储值的类型
        /// </summary>
        private ParamType xmlType = ParamType.OBJECT;

        /// <summary>
        ///  指定参数处理函数
        /// </summary>
        private string xmlFunc = string.Empty;

        public string XmlAddress { get => xmlAddress; set => xmlAddress = value; }
        public ParamType XmlType { get => xmlType; set => xmlType = value; }
        public string XmlFunc { get => xmlFunc; set => xmlFunc = value; }
    }
    public enum ParamType
    {
        INT=1,
        FLOAT=2,
        DOUBLE=3,
        STRING=4,
        OBJECT=5,
        USER=6
    }
}

2.标注我们的配置文件

namespace 秃顶韭菜的命名空间
{
    public class DemoConfig : ICustomizationConfig
    {
        [XmlMapping(XmlAddress = "//Id", XmlType =ParamType.INT)]
        public int Id { get; set; }

        [XmlMapping(XmlAddress = "//Code", XmlType = ParamType.STRING)]
        public string Code { get; set; }

        [XmlMapping(XmlAddress = "//Version", XmlType = ParamType.STRING)]
        public string Version { get; set; }

        [XmlMapping(XmlAddress = "//TestObject", XmlType = ParamType.USER, XmlFunc= "DemoUserParam")]
        public List<PointF> points { get; set; }

		/// <summary>
        /// 示例,对于特殊参数使用自定义解析方法
        /// </summary>
        /// <param name="xmlStr">读取自xml的字符串配置信息</param>
        /// <returns>注意这里的return类型必须要和你定义的属性类型一致,因为要填充的!</returns>
        public List<PointF> DemoUserParam(string xmlStr)
        {
            string[] pointStrs = xmlStr.Trim().Split('|');
            List<PointF> points = new List<PointF>();
            foreach (string pointStr in pointStrs)
            {
                string[] x_y = pointStr.Replace('(', ' ').Replace(')', ' ').Trim().Split(',');
                if (x_y.Length != 2)
                {
                    throw new Exception("娃,看看配置文件是不是整错了?中英文逗阔号啥的。");
                }
                 else
                {
                    PointF point = new PointF(int.Parse(x_y[0]), int.Parse(x_y[1]));
                    points.Add(point);
                }
            }
            return points;
        }  
    }
}   

3.配置文件示例

<?xml version="1.0" encoding="utf-8" ?>
<Config>
	<Id>100</Id>
	<Code>DFT01</Code>
	<UpdateTime>2020-12-31 19:06:00</UpdateTime>
	<Version>pigger</Version>
    <TestObject>(1,1)|(2,4)|(3,5)</TestObject>
</Config>

4.核心处理函数

读取attribute配置参数,并使用反射执行相关功能。

namespace 秃顶韭菜的命名空间
{
    public class ConfigReader
    {

        /// <summary>
        /// 从XML中读取配置
        /// </summary>
         /// <typeparam name="T">ICustomizationConfig 自定义的配置文件接口,可以不限定</typeparam>
        /// <param name="path">配置文件路径</param>
        /// <param name="rootName">xml根节点名称</param>
        /// <param name="configClass">配置文件对象</param>
        /// <returns></returns>
        public static bool ReadConfigFromXML<T>(string path, string rootName, ref T configClass)
            where T : ICustomizationConfig
        {
            XmlHelper xmlHelper = new XmlHelper(path, rootName);
            XmlDocument xmlDocument = xmlHelper.LoadXmlDocument();
            PropertyInfo[] propertyInfos = configClass.GetType().GetProperties();
            foreach (PropertyInfo info in propertyInfos)
            {
                // TODO 我们假设只使用一个标签,不存在多个,所以用first来获取
                XmlMapping mapping = info.GetCustomAttributes().First() as XmlMapping;
             	if (!string.IsNullOrEmpty(mapping.XmlAddress)) // 读取配置文件的地址
                {
                    string value = xmlHelper.GetInnerText(xmlDocument, mapping.XmlAddress);
                    switch (mapping.XmlType)
                    {
                   	   case ParamType.INT:
                            int valueInt = int.Parse(value);
                            info.SetValue(configClass, valueInt);
                            break;
                       case ParamType.DOUBLE:
                            double valueDouble = double.Parse(value);
                            info.SetValue(configClass, valueDouble);
                            break;
                       case ParamType.FLOAT:
                            float valueFloat = float.Parse(value);
                            info.SetValue(configClass, valueFloat);
                            break;
                       case ParamType.STRING:
                            info.SetValue(configClass, value);
                            break;
                       case ParamType.OBJECT:
                            info.SetValue(configClass, value);
                            break;
                       case ParamType.USER:
                            if (!string.IsNullOrEmpty(mapping.XmlFunc))
                            {
                                MethodInfo methodInfo = configClass.GetType().GetMethod(mapping.XmlFunc);
                                Object[] param = {value};
       							object res = methodInfo.Invoke(configClass, param);
                                info.SetValue(configClass, res);
                            }
                            else
                            {
                                throw new Exception("自定义处理函数时,XmlFunc指定的函数不能为空!");
                            }
                            break;
                     	default:
                            info.SetValue(configClass, value);
                            break;
                    }
                }
                else
                {
                    throw new Exception("XmlAddress不能为空!");
                }
            }
            return true;
        }
    }
}

5.使用它

只要在系统启动时调用,将其注入到实例即可,具体什么时候调用构建实例和注入,看应用场景。

DemoConfig config = new DemoConfig();
ConfigReader.ReadConfigFromXML(configPath, rootName, ref config);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值