LinqToExcel.Extend 源码分析

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

目录结构.png

目录结构功能

  • Extend 通用扩展方法
  • Parameter 公共实体类
  • Parser 解析器
  • Validate 验证工具集
目录结构展开.png

展开目录结构,我们能够更加请详细的分析出每个目录所完成的功能模块。
这里主要讲解工具集中最重要的一个模块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);
        }
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 34,818评论 18 399
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 3,162评论 2 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,680评论 19 139
  • 在未知中走向美好 彭水081赵陈 【未知】首先是一名教师,才得以成为一名青椒。 2017年夏季有幸成为...
    凝固的火阅读 346评论 0 0
  • 摩拜单车 第壹次听到“摩拜单车”的时候,是在壹档电视节目上,那时只知道是城市公共交通工具,是共享单车,并且供...
    傻先生阅读 376评论 0 2

友情链接更多精彩内容