IEnumerable<IEnumerable<string>>结构解析通用解决方案(支持指定属性顺序)
一、前言
类似如下字符串
"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() == )
{
return new List<T>();
} IList<T> entities = new List<T>();
var members = new DataMemberAttributeCollection(typeof(T), propertyNames); if (members.Count <= )
{
return new List<T>();
} FuncProvider funcProvider = new FuncProvider(); foreach (var propertyValues in entityRows)
{
if (propertyValues == null || propertyValues.Count() == )
{
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 == || propertyCount == )
{
return entity;
} int convertCount = Math.Min(memberCount, propertyCount);
DataMemberAttribute currAttribute;
PropertyInfo currPropertyInfo; int propertyValueIndex = ; foreach (string propertyValue in propertyValues)
{
if (propertyValueIndex >= convertCount)
{
break;
} propertyValueIndex++;
currAttribute = members[propertyValueIndex - ];
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 <= )
{
return;
} if (propertyNames == null || propertyNames.Length == )
{
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() > )
{
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) > )
{
throw new ArgumentException(string.Format(@"Contains Same Order {0}.Please Look Up DataMemberAttribute
Of 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>() { "", "NameValue", "CodeValue", "ExchangeTypeValue", "", "invalid" }); var contracts = ResultTransfer.Parse<ContinousContract>(entityRows); Assert.IsNotNull(contracts);
Assert.IsTrue(contracts.Count == );
Assert.AreEqual(contracts[].Code, "CodeValue");
Assert.AreEqual(contracts[].Name, "NameValue");
Assert.AreEqual(contracts[].ExchangeType, "ExchangeTypeValue");
Assert.AreEqual(contracts[].OrgidID, );
Assert.AreEqual(contracts[].ExchangeTypeValue, );
}
(2)对于只输入无效参数的应用如下:
[TestMethod()]
public void ParseWithInvalidArgTest()
{
IList<IList<string>> entityRows = new List<IList<string>>();
entityRows.Add(new List<string>() { "sss", "NameValue", "CodeValue", "ExchangeTypeValue", "", "invalid" }); var contracts = ResultTransfer.Parse<ContinousContract>(entityRows); Assert.IsNotNull(contracts);
Assert.IsTrue(contracts.Count == );
Assert.AreEqual(contracts[].Code, "CodeValue");
Assert.AreEqual(contracts[].Name, "NameValue");
Assert.AreEqual(contracts[].ExchangeType, "ExchangeTypeValue");
Assert.AreEqual(contracts[].OrgidID, );
Assert.AreEqual(contracts[].ExchangeTypeValue, );
}
输入无效的IEnumerable<IEnumerable<string>>参数,方法内部会进行隐式的转换,比如“sss”转换成0。
(3)对于二个参数时的应用如下:
[TestMethod()]
public void ParseWithArgTest()
{
IList<IList<string>> entityRows = new List<IList<string>>();
entityRows.Add(new List<string>() { "", "NameValue", "ExchangeTypeValue", "", "invalid" });
var propertyNames = new List<string>() { "ExchangeTypeValue", "Name", "", "ExchangeType" }; var contracts = ResultTransfer.Parse<ContinousContract>(entityRows, propertyNames.ToArray()); Assert.IsNotNull(contracts);
Assert.IsTrue(contracts.Count == );
Assert.AreEqual(contracts[].Code, null);
Assert.AreEqual(contracts[].Name, "NameValue");
Assert.AreEqual(contracts[].ExchangeType, "ExchangeTypeValue");
Assert.AreEqual(contracts[].OrgidID, );
Assert.AreEqual(contracts[].ExchangeTypeValue, );
}
一旦输入二个参数,且propertyNames参数的个数大于0,则以propertyNames对应的属性顺序进行解析。对于输入错误的属性名,方法内部会抛出异常,当然也可以增加一个参数用于控制是否抛出异常,或者写入日志文件中等。
对于将固定格式的字符串解析成IEnumerable<IEnumerable<string>>,正则表达式解析的话比较简单,此文不做讲解,略过...
IEnumerable<IEnumerable<string>>结构解析通用解决方案(支持指定属性顺序)的更多相关文章
- 一位有着工匠精神的博主写的关于IEnumerable接口的详细解析
在此,推荐一位有着工匠精神的博主写的一篇关于IEnumerable接口的深入解析的文章:http://www.cnblogs.com/zhaopei/p/5769782.html#autoid-0-0 ...
- iOS沙盒目录结构解析
iOS沙盒目录结构解析 原文地址:http://blog.csdn.net/wzzvictory/article/details/18269713 出于安全考虑,iOS系统的沙盒机制规定每个应 ...
- 逆天通用水印支持Winform,WPF,Web,WP,Win10。支持位置选择(9个位置 ==》[X])
常用技能:http://www.cnblogs.com/dunitian/p/4822808.html#skill 逆天博客:http://dnt.dkil.net 逆天通用水印扩展篇~新增剪贴板系列 ...
- 业务安全通用解决方案——WAF数据风控
业务安全通用解决方案——WAF数据风控 作者:南浔@阿里云安全 “你们安全不要阻碍业务发展”.“这个安全策略降低用户体验,影响转化率”——这是甲方企业安全部门经常听到合作团队抱怨.但安全从业者加入公司 ...
- Spring Web MVC 多viewResolver视图解析器解决方案
viewResolver的定义如下: public interface ViewResolver { View resolveViewName(String viewName, Locale loca ...
- H.264码流结构解析
from:http://wenku.baidu.com/link?url=hYQHJcAWUIS-8C7nSBbf-8lGagYGXKb5msVwQKWyXFAcPLU5gR4BKOVLrFOw4bX ...
- Redis源码剖析--源码结构解析
请持续关注我的个人博客:https://zcheng.ren 找工作那会儿,看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识.在面试过程中,redis确实 ...
- InfluxDB源码目录结构解析
操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 influxdata主目录结构 [root@localhost ...
- Atitit 大json文件的结构化查看解决方案,高性能的jsonview attilax总结.docx
Atitit 大json文件的结构化查看解决方案,高性能的jsonview attilax总结.docx 1.1. 实现目标:1 1.2. 实现key与value类型的..一直分析到非 jsonob ...
随机推荐
- 脚本录制(JMeter)
使用JMeter录制脚本: 1.打开JMeter工具,创建一个线程组,接着创建一个http代理服务器,代理服务器设置如下:
- 蚁群算法求解旅行商问题(附c和matlab源代码)
前几天写了个模拟退火算法的程序,然后又陆陆续续看了很多群智能算法,发现很多旅行商问题都采用蚁群算法来求解,于是开始写蚁群算法的模板.网上关于蚁群算法的理论很多就不再这里赘述了,下面直接上代码和进行简单 ...
- 解决mac升级后,出现的 xcrun: error: invalid active developer path, missing xcrun 错误
最近升级了mac系统,然后接着写代码就出问题了. 报错信息如下: xcrun: error: invalid active developer path (/Library/Developer/Com ...
- Robot Framework入门学习2 创建第一个测试用例
本文章部分内容引自以下网址,感谢作者的辛苦分享 http://www.cnblogs.com/fnng/p/3871712.html http://blog.csdn.net/tulituqi/art ...
- Linux多线程服务端编程一些总结
能接触这本书是因为上一个项目是用c++开发基于Linux的消息服务器,公司没有使用第三方的网络库,卷起袖子就开撸了.个人因为从业经验较短,主 要负责的是业务方面的编码.本着兴趣自己找了这本书.拿到书就 ...
- C# ToString("x2")的理解
1).转化为16进制. 2).大写X:ToString("X2")即转化为大写的16进制. 3).小写x:ToString("x2")即转化为小写的16进制. ...
- mac iterm2配置
iterm2的配置分为如下几个部分: 1. 字体大小的配置: iTerm->Preferences->Profiles->Text->Regular Font: 我在这里设置成 ...
- IE6的连接数限制问题
今天解决了一个bug.看似是UI的bug,最后发现IE的设置问题(严格来说,IE6这么做没有问题,因为HTTP协议的规范如此). 先描述一下问题: 有一个页面管理Job,选中一些Job可以Run,每次 ...
- MySQL数据库安装与配置详解
转载提示:在原文http://www.cnblogs.com/sshoub/p/4321640.html基础上修改. 目录 一.概述 二.MySQL安装 三.安装成功验证 四.NavicatforMy ...
- [WPF]设置背景色
程序效果 最终得到程序的运行效果如图.拖动Slider可以使按钮的背景色出现相应变化. 需求分析和架构设计 如果是你,接到了这样的一个程序设计要求,会怎样思考?第一步当然是需求分析啦.这个程序相对简单 ...