写点什么

LinqToExcel.Extend 源码分析

用户头像
happlyfox
关注
发布于: 2021 年 03 月 07 日

废话不多说,我们直接来分析源码,首先我们查看目录结构


目录结构功能

  • Extend 通用扩展方法

  • Parameter 公共实体类

  • Parser 解析器

  • Validate 验证工具集


展开目录结构,我们能够更加请详细的分析出每个目录所完成的功能模块。

这里主要讲解工具集中最重要的一个模块 Validate


要设计,我们就一定要知道自己想怎么做。

如果我对外提供接口调用,怎么样的方式是最方便,让人容易理解的,我就是朝着这个方向做的。

我希望的结果是

实例化验证对象,参数是验证文件的路径

调用验证方法,可以区分工作表验证,可以选择添加或不添加逻辑验证

验证成功或失败都返回一个对象,如果验证失败,返回的对象中要包含出错的信息(尽可能细化)



基于上述的设计理念

我定义了三个对象

RowValidate 行验证

WorkSheetValidate 工作表验证

WorkBookValidate 工作簿验证


RowValidate 行验证

>RowValidate 对象执行的调用方是 WorkSheetValidate

Validate<T>执行返回值为 得到当前行的的出错信息集合

    /// <summary>    /// 行验证    /// </summary>    public class RowValidate    {        public static string GetCellStation(int rowIndex, int columnIndex)        {            int i = columnIndex % 26;            string cellRef = Convert.ToChar(65 + i).ToString() + (rowIndex + 1);            return cellRef;        }
public static List<ErrCell> Validate<T>(int rowIndex, List<string> colNames, List<int> colIndexs, List<string> rowCellValues) { List<ErrCell> errCells = new List<ErrCell>(); T singleT = Activator.CreateInstance<T>();
foreach (PropertyInfo pi in singleT.GetType().GetProperties()) { var propertyAttribute = (Attribute.GetCustomAttribute(pi, typeof(ExcelColumnAttribute))); if (propertyAttribute == null) { continue; } var proName = ((ExcelColumnAttribute)propertyAttribute).ColumnName; for (int colIndex = 0; colIndex < colNames.Count; colIndex++) { try { if (proName.Equals(colNames[colIndex], StringComparison.OrdinalIgnoreCase)) { string fieldName = pi.PropertyType.GetUnderlyingType().Name; string cellValue = rowCellValues[colIndex];
if (!String.IsNullOrWhiteSpace(cellValue)) { //如果是日期类型,特殊判断 if (fieldName.Equals("DateTime")) { string data = ""; try { data = cellValue.ToDateTimeValue(); } catch (Exception) { data = DateTime.Parse(cellValue).ToString(); } } cellValue.CastTo(pi.PropertyType); } } } catch (Exception ex) { errCells.Add(new ErrCell() { RowIndex = rowIndex, ColumnIndex = colIndexs[colIndex], Name = GetCellStation(rowIndex, colIndexs[colIndex]), ErrMsg = ex.Message }); } } } return errCells; } }
复制代码


##WorkBookValidate 工作簿验证

>WorkBookValidate 是根的验证对象。我们首先看构造函数,参数为 filePath,在构造函数中,我们做的操作是:实例化 N 个 WorkSheetValidate 对象。

定义索引器,这样可以通过外部调用 WorkSheetValidate 的验证方法

   /// <summary>    /// 工作簿验证    /// </summary>    public class WorkBookValidate    {        public string FilePath { get; set; }
private List<WorkSheetValidate> _workSheetList = new List<WorkSheetValidate>();
public List<WorkSheetValidate> WorkSheetList { get { return _workSheetList; } set { _workSheetList = value; } }
public WorkSheetValidate this[string sheetName] { get { foreach (WorkSheetValidate sheetParameterContainer in _workSheetList) { if (sheetParameterContainer.SheetName.Equals(sheetName)) { return sheetParameterContainer; } } throw new Exception("工作表不存在"); } }
public WorkSheetValidate this[int sheetIndex] { get { foreach (WorkSheetValidate sheetParameterContainer in _workSheetList) { if (sheetParameterContainer.SheetIndex.Equals(sheetIndex)) { return sheetParameterContainer; } } throw new Exception("工作表不存在"); } }
/// <summary> /// /// </summary> /// <param name="filePath">路径</param> public WorkBookValidate(string filePath) { FilePath = filePath; var excel = new ExcelQueryFactory(filePath); List<string> worksheetNames = excel.GetWorksheetNames().ToList();
int sheetIndex = 0; foreach (var sheetName in worksheetNames) { WorkSheetList.Add(new WorkSheetValidate(filePath, sheetName, sheetIndex++)); } } }
复制代码


##WorkSheetValidate 工作表验证

>这是这三个验证模块中最复杂的一个,代码就不贴全部的图了,主要讲解一下重要的地方。

首先也是构造函数,这个构造函数主要是给 WorkBookVaidate 调用

      public WorkSheetValidate(string filePath, string sheetName, int sheetIndex)        {            FilePath = filePath;            SheetName = sheetName;            SheetIndex = sheetIndex;
TootarIndex = 0; }
复制代码

>验证方法说明

这是一个泛型方法,方法逻辑很简单

首先验证数据有效性 ValidateParameter

如果返回的错误集合为空,验证逻辑有效性 ValidateMatching

最后返回验证集合


    public Verification StartValidate<T>(List<CellMatching<T>> rowValidates = null)        {            List<ErrCell> errCells = this.ValidateParameter<T>(TootarIndex);            if (!errCells.Any())            {                TootarIndex += 1;                errCells.AddRange(this.ValidateMatching<T>(rowValidates, TootarIndex));            }
Verification validate = new Verification();
if (errCells.Any()) { validate = new Verification() { IfPass = false, ErrCells = errCells }; } else { validate = new Verification() { IfPass = true, ErrCells = errCells }; }
return validate; }
复制代码


##验证数据有效性

>这个模块相对复杂,看不懂的小伙伴可以多看几遍理解消化吸收下。

首先调用 LinqToExcel 的 WorksheetNoHeader 方法获得除了标题的集合数据

然后得到当前标题行和 Excel 列的映射关系

调用 GetErrCellByParameter 方法进行验证


>GetErrCellByParameter 说明

得到所有列名称集合,得到所有列名称索引

遍历行数据,调用 RowValidate 的静态方法 RowValidate.Validate<T>

传递的参数是,行索引,列名称集合,列索引集合,行数据集合

  private List<ErrCell> GetErrCellByParameter<T>(List<RowNoHeader> rows, int startRowIndex)        {            List<string> colNames = _propertyCollection.Values.Select(u => u.ColName).ToList();            List<int> colIndexs = _propertyCollection.Values.Select(u => u.ColIndex).ToList();
List<ErrCell> errCells = new List<ErrCell>(); for (int rowIndex = startRowIndex; rowIndex < rows.Count; rowIndex++) { List<string> rowValues = rows[rowIndex].Where((u, index) => colIndexs.Any(p => p == index)).Select(u => u.ToString()).ToList(); errCells.AddRange(RowValidate.Validate<T>(rowIndex, colNames, colIndexs, rowValues)); } return errCells; }
复制代码


    private List<ErrCell> ValidateParameter<T>(int startRowIndex)        {            //第一步 得到集合            var excel = new ExcelQueryFactory(FilePath);            var rows = (from c in excel.WorksheetNoHeader(SheetIndex)                        select c).ToList();            //第二步 获得标题行和Excel列的映射关系                 方法体省略
//第二步 调用验证方法 return GetErrCellByParameter<T>(rows, startRowIndex); }
复制代码


发布于: 2021 年 03 月 07 日阅读数: 14
用户头像

happlyfox

关注

公众号 程序员工具集 2021.02.18 加入

博客 [www.zhouhuibo.club] 分享优秀的开源项目、学习资源和常用工具。谈论新闻热点、职场经验、学习感悟。共同进步!

评论

发布
暂无评论
LinqToExcel.Extend 源码分析