.Net Epplus读取excel转List<T>

在.net中说到对excel的读取大家首先想到的可能是NPOI、LinqToExcel,最近在项目中用到Epplus,觉得也不错。

Epplus可以在NuGet中安装

我想达到的效果是导入Excel,直接转成想要的泛型集合。

我有个Person的类

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime? Birthday { get; set; }
}

希望最后的使用可能是这样的

var list =  worksheet.ConvertSheetToObjects<Person>();

想一想...该怎么做.......

1、自定义Attribute

告诉Person类型 Name对应-->"姓名",Age对应-->"年龄",Birthday对应-->"生日"。

所以我们需要自己先定义这个标签类:

    /// <summary>
    /// 自定义excel头部标签
    /// </summary>
    [AttributeUsage(AttributeTargets.All)]
    public class ExcelColumn : Attribute
    {
        /// <summary>
        /// 标签名称
        /// </summary>
        public string ColumnName { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name"></param>
        public ExcelColumn(string name)
        {
            ColumnName = name;
        }
    }

2、给Person类的字段设置标签

public class Person
{
  [ExcelColumn("姓名")]
  public string Name { get; set; }

  [ExcelColumn("年龄")]
  public int Age { get; set; }

  [ExcelColumn("生日")]
  public DateTime? Birthday { get; set; }
}

3、对Epplus进行扩展,写个扩展类吧

 public static class EppLusExtensions
    {
        /// <summary>
        /// 获取标签对应excel的Index
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="columnName"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static int GetColumnByName(this ExcelWorksheet ws, string columnName)
        {
            if (ws == null) throw new ArgumentNullException(nameof(ws));
            return ws.Cells["1:1"].First(c => c.Value.ToString() == columnName).Start.Column;
        }
        /// <summary>
        /// 扩展方法
        /// </summary>
        /// <param name="worksheet"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<T> ConvertSheetToObjects<T>(this ExcelWorksheet worksheet) where T : new()
        {

            Func<CustomAttributeData, bool> columnOnly = y => y.AttributeType == typeof(ExcelColumn);
            var columns = typeof(T)
                .GetProperties()
                .Where(x => x.CustomAttributes.Any(columnOnly))
                .Select(p => new
                {
                    Property = p,
                    Column = p.GetCustomAttributes<ExcelColumn>().First().ColumnName 
                }).ToList();

            var rows = worksheet.Cells
                .Select(cell => cell.Start.Row)
                .Distinct()
                .OrderBy(x => x);

            var collection = rows.Skip(1)
                .Select(row =>
                {
                    var tnew = new T();
                    columns.ForEach(col =>
                    {
                        var val = worksheet.Cells[row, GetColumnByName(worksheet, col.Column)];
                        if (val.Value == null)
                        {
                            col.Property.SetValue(tnew, null);
                            return;
                        }
                        // 如果Person类的对应字段是int的,该怎么怎么做……
                        if (col.Property.PropertyType == typeof(int))
                        {
                            col.Property.SetValue(tnew, val.GetValue<int>());
                            return;
                        }
                        // 如果Person类的对应字段是double的,该怎么怎么做……
                        if (col.Property.PropertyType == typeof(double))
                        {
                            col.Property.SetValue(tnew, val.GetValue<double>());
                            return;
                        }
                        // 如果Person类的对应字段是DateTime?的,该怎么怎么做……
                        if (col.Property.PropertyType == typeof(DateTime?))
                        {
                            col.Property.SetValue(tnew, val.GetValue<DateTime?>());
                            return;
                        }
                        // 如果Person类的对应字段是DateTime的,该怎么怎么做……
                        if (col.Property.PropertyType == typeof(DateTime))
                        {
                            col.Property.SetValue(tnew, val.GetValue<DateTime>());
                            return;
                        }
                        // 如果Person类的对应字段是bool的,该怎么怎么做……
                        if (col.Property.PropertyType == typeof(bool))
                        {
                            col.Property.SetValue(tnew, val.GetValue<bool>());
                            return;
                        }
                        col.Property.SetValue(tnew, val.GetValue<string>());
                    });

                    return tnew;
                });
            return collection;
        }
    }

4、使用

这里我模拟http上传了一个excel来进行操作。如果你是读取本地excel请自行脑补IO流的玩法或者加我微信63036596然后给我100块钱我教你

[HttpPost]
[Route("Import")]
public void Import()
{
   var file = HttpContext.Current.Request.Files[0];
   var package = new ExcelPackage(file.InputStream);
   var workbook = package.Workbook;
   var worksheet = workbook.Worksheets.First();
   var result = worksheet.ConvertSheetToObjects<Person>().ToArray();
}

好了,可以愉快的玩耍了

猜你喜欢

转载自blog.csdn.net/hbxixi20549/article/details/80773929