一、前言

类似如下字符串

"ID", "NameValue", "CodeValue", "ExchangeTypeValue", 6, "invalid"

"ID2", "NameValue2", "CodeValue2", "ExchangeTypeValue2", 6, "invalid"

.......

有可能是文件中存在的,或者调用其他程序返回的结构化数据,那么该如何解析?当其他场景中,只是返回顺序(属性顺序)变了,类结构还是一样,又如何应对?当有很多类似场景时,是不是该抽象出一个泛型方法来应对该场景?当然,也不仅仅于上述情况,可能返回的结构是确定,只是形式不一样,这个过程这里暂时省略,因为正则表达式完全能够解析出来。要用以下的方法,必须转换成IEnumerable<IEnumerable<string>>结构,IEnumerable<IEnumerable<string>>结构中IEnumerable<string>为一个对象所有的值,总体是多个对象的值集合。本文中用反射写的(关于IL操作的后续文章提供),相关的类图如下:

二、ResultTransfer的具体实现

ResultTransfer主要用于对IEnumerable<IEnumerable<string>>结构的解析,另外还可以指定params string[] propertyNames属性参数列表来确定解析顺序(也即是属性顺序),主要方法如下:

public static IList<T> Parse<T>(IEnumerable<IEnumerable<string>> entityRows, params string[] propertyNames) where T : new()

第一个参数entityRows为对象列表值集合。

第二个参数propertyNames为可选参数,输入该参数后,如果propertyNames中存在相关属性,则按照propertyNames对应的属性顺序进行解析。否则按照提供的T类中属性的DataMemberAttribute来确定属性顺序进行解析。

实现代码非常简洁和简单,方法具体如下所示:

        public static IList<T> Parse<T>(IEnumerable<IEnumerable<string>> entityRows, params string[] propertyNames) where T : new(){if (entityRows == null || entityRows.Count() == 0){return new List<T>();}IList<T> entities = new List<T>();var members = new DataMemberAttributeCollection(typeof(T), propertyNames);if (members.Count <= 1){return new List<T>();}FuncProvider funcProvider = new FuncProvider();foreach (var propertyValues in entityRows){if (propertyValues == null || propertyValues.Count() == 0){continue;}entities.Add(Generate<T>(propertyValues, members, funcProvider));}return entities;}private static T Generate<T>(IEnumerable<string> propertyValues, DataMemberAttributeCollection members,FuncProvider funcProvider) where T : new(){T entity = Activator.CreateInstance<T>();int memberCount = members.Count;int propertyCount = propertyValues.Count();if (memberCount == 0 || propertyCount == 0){return entity;}int convertCount = Math.Min(memberCount, propertyCount);DataMemberAttribute currAttribute;PropertyInfo currPropertyInfo;int propertyValueIndex = 0;foreach (string propertyValue in propertyValues){if (propertyValueIndex >= convertCount){break;}propertyValueIndex++;currAttribute = members[propertyValueIndex - 1];currPropertyInfo = currAttribute.PropertyInfo;if (propertyValue == null){currPropertyInfo.SetValue(entity, null, null);continue;}if (propertyValue.GetType() == currAttribute.PropertyType){currPropertyInfo.SetValue(entity, propertyValue, null);}else{object result = funcProvider.DynamicInvoke(currAttribute.PropertyType, (propertyValue ?? string.Empty).ToString());currPropertyInfo.SetValue(entity, result, null);}}return entity;}

三、DataMemberAttributeCollection的具体实现

DataMemberAttributeCollection集合类主要用于设置解析属性的顺序,同样,该类提供二个参数的构造函数用于生成相应的配置信息public DataMemberAttributeCollection(Type type, params string[] propertyNames)。

主要代码如下:

        public void GetConfiguration(Type type, params string[] propertyNames){if (type == null || type.GetProperties().Length <= 0){return;}if (propertyNames == null || propertyNames.Length == 0){AddAllDataMemberAttributes(type);}else{AddDataMemberAttributes(type, propertyNames);}this._memberAttributes = this._memberAttributes.OrderBy(p => p.Order).ToList();}private void AddDataMemberAttributes(Type type, string[] propertyNames){IList<PropertyInfo> validPropertyInfos = new List<PropertyInfo>();PropertyInfo tempPropertyInfo;foreach (string propertyName in propertyNames){if (string.IsNullOrWhiteSpace(propertyName)){continue;}tempPropertyInfo = type.GetProperty(propertyName.Trim());if (tempPropertyInfo == null){throw new ArgumentException(string.Format(@"Contains Invalid Property Name Arg : {0}.", propertyName.Trim()));}validPropertyInfos.Add(tempPropertyInfo);}if (validPropertyInfos.Count() > 0){foreach (var property in validPropertyInfos){AddAttributes(new DataMemberAttribute(), property);}}}private void AddAllDataMemberAttributes(Type type){DataMemberAttribute attr = null;foreach (PropertyInfo propertyInfo in type.GetProperties()){attr = AttributeUtility.GetCustomAttribute<DataMemberAttribute>(propertyInfo);if (attr == null){continue;}if (!attr.IsRequire){continue;}if (this._memberAttributes.Count(p => p.Order == attr.Order) > 0){throw new ArgumentException(string.Format(@"Contains Same Order {0}.Please Look Up DataMemberAttributeOf The Type {1}", attr.Order, type.Name));}AddAttributes(attr, propertyInfo);}}private void AddAttributes(DataMemberAttribute attr, PropertyInfo propertyInfo){if (string.IsNullOrWhiteSpace(attr.Name)){attr.Name = propertyInfo.Name;}attr.PropertyName = propertyInfo.Name;attr.PropertyType = propertyInfo.PropertyType;attr.PropertyInfo = propertyInfo;this._memberAttributes.Add(attr);}

该类确保指定Type的类中DataMemberAttribute是否设置正确(是否有相同的Order),确保是否输入了错误的propertyName。

四、具体应用

对于具体应用的话,用单元测试来得方便与直接。

(1)对于只输入一个参数的应用如下:

        [TestMethod()]public void ParseTest(){IList<IList<string>> entityRows = new List<IList<string>>();entityRows.Add(new List<string>() { "3", "NameValue", "CodeValue", "ExchangeTypeValue", "6", "invalid" });var contracts = ResultTransfer.Parse<ContinousContract>(entityRows);Assert.IsNotNull(contracts);Assert.IsTrue(contracts.Count == 1);Assert.AreEqual(contracts[0].Code, "CodeValue");Assert.AreEqual(contracts[0].Name, "NameValue");Assert.AreEqual(contracts[0].ExchangeType, "ExchangeTypeValue");Assert.AreEqual(contracts[0].OrgidID, 3);Assert.AreEqual(contracts[0].ExchangeTypeValue, 6);}

(2)对于只输入无效参数的应用如下:

        [TestMethod()]public void ParseWithInvalidArgTest(){IList<IList<string>> entityRows = new List<IList<string>>();entityRows.Add(new List<string>() { "sss", "NameValue", "CodeValue", "ExchangeTypeValue", "6", "invalid" });var contracts = ResultTransfer.Parse<ContinousContract>(entityRows);Assert.IsNotNull(contracts);Assert.IsTrue(contracts.Count == 1);Assert.AreEqual(contracts[0].Code, "CodeValue");Assert.AreEqual(contracts[0].Name, "NameValue");Assert.AreEqual(contracts[0].ExchangeType, "ExchangeTypeValue");Assert.AreEqual(contracts[0].OrgidID, 0);Assert.AreEqual(contracts[0].ExchangeTypeValue, 6);}

输入无效的IEnumerable<IEnumerable<string>>参数,方法内部会进行隐式的转换,比如“sss”转换成0。

(3)对于二个参数时的应用如下:

        [TestMethod()]public void ParseWithArgTest(){IList<IList<string>> entityRows = new List<IList<string>>();entityRows.Add(new List<string>() { "3", "NameValue", "ExchangeTypeValue", "6", "invalid" });var propertyNames = new List<string>() { "ExchangeTypeValue", "Name", "", "ExchangeType" };var contracts = ResultTransfer.Parse<ContinousContract>(entityRows, propertyNames.ToArray());Assert.IsNotNull(contracts);Assert.IsTrue(contracts.Count == 1);Assert.AreEqual(contracts[0].Code, null);Assert.AreEqual(contracts[0].Name, "NameValue");Assert.AreEqual(contracts[0].ExchangeType, "ExchangeTypeValue");Assert.AreEqual(contracts[0].OrgidID, 0);Assert.AreEqual(contracts[0].ExchangeTypeValue, 3);}

一旦输入二个参数,且propertyNames参数的个数大于0,则以propertyNames对应的属性顺序进行解析。对于输入错误的属性名,方法内部会抛出异常,当然也可以增加一个参数用于控制是否抛出异常,或者写入日志文件中等。

对于将固定格式的字符串解析成IEnumerable<IEnumerable<string>>,正则表达式解析的话比较简单,此文不做讲解,略过...

IEnumerableIEnumerablestring结构解析通用解决方案(支持指定属性顺序)相关推荐

  1. 《ASP.NET Core In Action》读书笔记系列五 ASP.NET Core 解决方案结构解析1

    <ASP.NET Core In Action>读书笔记系列五 ASP.NET Core 解决方案结构解析1 参考文章: (1)<ASP.NET Core In Action> ...

  2. iOS沙盒目录结构解析

    iOS沙盒目录结构解析 原文地址:http://blog.csdn.net/wzzvictory/article/details/18269713 出于安全考虑,iOS系统的沙盒机制规定每个应用都只能 ...

  3. 移动办公通用解决方案

    移动办公通用解决方案 相关PPT 相关音视频   市场背景 随着办公自动化系统的普及,电子化.数据化的办公方式已进入越来越多的企业和政府单位,信息化的办公系统在企事业内部编织起一套高效.畅通的信息互联 ...

  4. 机器视觉技术原理解析及解决方案

    机器视觉技术原理解析及解决方案 机器视觉就是用机器代替人眼来做测量和判断.机器视觉系统是指通过机器视觉产品(即图像摄取装置,分 CMOS 和CCD 两种)将被摄取目标转换成图像信号,传送给专用的图像处 ...

  5. Chrome 扩展 H5 游戏结构检查器 GameInspect 支持 Laya, egret, cocosCreate, cocos2d-js

    Chrome 扩展 H5 游戏结构检查器 GameInspect 支持 Laya, egret, cocosCreate, cocos2d-js 1. 说明 仿照 egret Inspect 制作的通 ...

  6. 技术的真相 | 视频智能分析之Web视频播放通用解决方案

    通常,摄像机H265视频编码在传输快.存储小.画质高等方面的优势使得其备受企业青睐,但是由于主流浏览器不能够支持这种格式,因此在浏览器下播放和解析视频都受到一定的约束.那么,如何实现 Web 视频播放 ...

  7. vsc 搜索特定代码_特定问题的通用解决方案:何时编写代码以及何时编写代码...

    vsc 搜索特定代码 by Rina Artstain 通过丽娜·阿斯特斯坦 特定问题的通用解决方案:何时编写代码以及何时编写代码 (Generic solutions to specific pro ...

  8. windows PE结构解析

    1 基本概念 下表描述了贯穿于本文中的一些概念: 名称 描述 地址 是"虚拟地址"而不是"物理地址".为什么不是"物理地址"呢?因为数据在内 ...

  9. 智能音箱硬件和软件介绍[上] 硬件结构解析[Soomal]

    科大讯飞 VBOX 智能音箱 - 电路板 Google 谷歌 Google Home 智能音箱 从2014年起,我们先后通过自购和合作厂商获得多个智能语音识别"流派"的品牌音箱产品 ...

  10. 3DCAD图纸转2D(DXF)图纸通用解决方案文稿

    3DCAD图纸转2D(DXF)图纸通用解决方案文稿 本文地址:https://gitee.com/dvaloveu/lovedva/issues/I6B5YC 视频演示(1.25倍速&原速): ...

最新文章

  1. mysql where关键字_MySQL WHERE 子句
  2. Luogu P2580 于是他错误的点名开始了 Trie树 字典树
  3. [云炬创业基础笔记] 第四章测试11
  4. 前端学习(3303):函数组件组件子组件useRef聚焦
  5. java 创建线程的三种方法_java 创建线程的几种方式
  6. Visual Studio调试之断点基础篇
  7. 分配内存的方法,需要32位对齐
  8. 【java】java AsyncHttpClient使用
  9. oracle透明网关访问sqlserver_基于智慧照明网关的地下停车场照明解决方案
  10. 请解释一下 str db 0dh,0ah,‘$‘ 这个汇编语句什么意思?
  11. 三层架构学习的困难_TCP/IP协议栈-之-三层交换技术
  12. 计算机职称评定认可增刊吗,核心期刊增刊评定职称可以用吗?
  13. c语言编程流水灯与交通灯实验,51单片机c语言交灯设计报告.doc
  14. n9 android模拟器,Android软件将兼容诺基亚N9
  15. python打印万年历_你会用Python打印一个万年历吗?像月历一样好看!
  16. html里怎么画斜线表头,excel里斜线表头怎么做
  17. 汇编语言——偏移地址超过有效地址FFFFH
  18. 调用Powergui FFT Analysis Tool进行FFT分析
  19. 解决谷歌翻译用不了的问题
  20. linux中怎么卸载桌面图标,如何从Ubuntu 18.04桌面上删除垃圾桶图标

热门文章

  1. 如何以管理员方式管理文件
  2. 【已经解决】TypeError: read_img() missing 1 required positional argument: ‘filename‘
  3. Java之strictfp关键字
  4. 利用composer搭建PHP框架(一.路由解析)
  5. 百战java课程_java百战程序员SpringBoot视频教程
  6. 使用Pycharm管理Python依赖库(不使用anaconda)
  7. JavaEE学习05--cookiesession
  8. slxrom+v.21+原生android+4.2,小米4移动联通版 魔趣OS 安卓10 MagiskV21版 完美ROOT 纯净完美 原生极简 纯净推荐...
  9. 收藏+下载!Flink 社区最全学习渠道汇总
  10. 【系列】关于直播,所有的技术细节都在这里了