• SilverLight系列——通过反射获取或设置指定属性路径表达式的值


          本来反射是跟SilverLight是没有必然联系的,之所以把这一篇随笔也冠以“SilverLight系列”的前缀,是因为这一篇里所讲的内容确实是在做SilverLight开发时才决心要做的。相信涉猎过SilverLight的人都会见过类似于如下的XAML代码:

          <TextBox Text=”{Binding Path=[0].Name}” />

          记得一开始看到"[0].Name”这种表达式时就觉得SilverLight里的绑定真是强大,而且也预感在接下来的SL的开发中,如果能使用类似于GetPropertyValue(“[0].Name”)这种方法的话是能够带来多大的方便,于是就决定要实现这一应用。实现起来包含以下几点思路:

          1、定义成object类型的扩展方法,方便使用;

          2、解析属性路径表达式(即[0].Name这种),获取有序的属性定义集合;

          3、对于GetPropertyValue,根据解析而得的属性定义集合,通过循环获取的方式,取出最终值,如[0].Name,实际上应取集合中第一个元素的Name属性值;

          4、对于SetPropertyValue,根据解析而得的属性定义集合,获取倒数第二个值,再设置最后一个属性值,如[0].Name,应先获取集合第一个元素,然后再设置这个元素的Name值;

          5、暂不考虑复杂类型的索引器属性,即仅支持参数类型为int或string的索引器;

          先自定义一个类用于标识一个属性:

        private class PropInfo
        {
            /// <summary>
            /// 属性名
         /// </summary>
            public string Name = "";
            /// <summary>
            /// 是否为索引器属性
         /// </summary>
            public bool IsIndexer = false;
            /// <summary>
            /// 索引器参数是否为整型
          /// </summary>
            public bool IsNumberIndexer = false;
        }
        由于不需要做任何赋值上的处理,所以并没应定义成属性的形式。之所以需要标明是否为整型,是因为通过PropertyInfo.GetValue方法来获取值时,需要指定参
    数类型。
        为了尽量减少重复的解析动作,使用一个静态成员将已解析过的属性路径缓存起来: 
        private static readonly Dictionary<string, List<PropInfo>> PropertyCache = new Dictionary<string, List<PropInfo>>();    
        然后便是用于检测属性路径合法性的正则表达式: 
       /// <summary>
        /// 检测属性路径字符串是否合法的正则表达式
       /// </summary>
        private static readonly Regex RegPropertyPath = new Regex(@"(\d|\w|(\[(\d|\w)+\])|\.)+");
        /// <summary>
        /// 检测是否为数字
       /// </summary>
        private static readonly Regex RegNumber = new Regex(@"\d+"); 
     
        解析属性路径表达式的算法很简单,按字符读取,做一些条件判断即可:
       /// <summary>
        /// 解析属性路径字符串
       /// </summary>
        /// <param name="propertyPath">将属性路径字符串解析为属性描述数组</param>
        /// <returns></returns>
        private static List<PropInfo> AnalyzePropertyPath(string propertyPath)
        {
            propertyPath = propertyPath + "$";
    
            if (PropertyCache.ContainsKey(propertyPath))
                return PropertyCache[propertyPath];
    
            List<PropInfo> proInfoList = new List<PropInfo>();
            PropInfo proInfo = null;
            for (int i = 0; i < propertyPath.Length; i++)
            {
                char c = propertyPath[i];
                if (c == '[')
                {
                    if (proInfo == null)
                    {
                        proInfo = new PropInfo() { IsIndexer = true };
                    }
                    else
                    {
                        if (proInfo.Name == "")
                        {
                            throw new AnalyzePropertyException("analyze propertypath failed!");
                        }
                        else
                        {
                            proInfoList.Add(proInfo);
                            proInfo = new PropInfo(){ IsIndexer = true};
                        }
                    }
                    continue;
                }
                //属性结尾
                if (c == ']' || c == '.')
                {
                    if (proInfo != null)
                    {
                        if (proInfo.Name == "")
                        {
                            throw new AnalyzePropertyException("analyze propertypath failed, unknown property:[]");
                        }
                        else
                        {
                            if (RegNumber.IsMatch(proInfo.Name))
                                proInfo.IsNumberIndexer = true;
                            proInfoList.Add(proInfo);
                            proInfo = null;
                        }
                    }
                    continue;
                }
                //最后一个属性
                if (c == '$' && proInfo != null)
                {
                    proInfoList.Add(proInfo);
                    break;
                }
                //累计属性名中的字符
                if (proInfo == null)
                {
                    proInfo = new PropInfo();
                }
                proInfo.Name = proInfo.Name + c.ToString();
            }
    
            PropertyCache.Add(propertyPath, proInfoList);
    
            return proInfoList;
        } 
     
        获取值跟设置值的方法我就不贴出来了,省得一篇随笔下来放眼过去全是代码。使用方法示例: 
     
        List<Person> persons = new List<Person>() { new Person() { Name = "lfx" } };
         string name = (string)persons.GetPropertyValue("[0].Name"); //获取值
        persons.SetPropertyValue("[0].Name", "hello lfx");  //设置值
     
        完整代码请点击链接下载:ObjectExtention.rar
     
  • 相关阅读:
    机器学习-liuyubobobo(慕课网)
    python进阶 廖雪峰(慕课网)
    ajax 报0错误
    nav破解
    thinkphp5--关于多条件查询的分页处理问题
    JS/JQuery获取当前元素的上一个/下一个兄弟级元素等元素的方法
    linux 批量删除文件
    Linux下which命令使用详解(转)
    thinkphp5和nginx不得不说的故事
    Git基本操作和使用
  • 原文地址:https://www.cnblogs.com/sdlfx/p/2141508.html
Copyright © 2020-2023  润新知