栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

C#将List模型直接导出为Excel

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C#将List模型直接导出为Excel

首先,新的一年祝大家新年快乐。
元旦也是浪了几天没怎么写东西,但必须趁着新的一年赶快开动起来

前言:

在学习了NPOI操作Excel并完成了打印报表的经历后,
个人有一些感觉,
1.用DataTable导Excel还是太麻烦
2.使用Dapper等ORM的工具,再把结果变成Datatable(个人觉得是个带壳的二维数组)和orm的概念冲突,很别扭
所有觉得有必要写个工具直接把直接把List转化为Excel,不用经过DataTable这种东西,也能和ORM一起使用,
虽然实际的开发可能因为ExceL格式的要求而使用空间不大,但总归是要有。
这个工具我已经放在码云上,地址:https://gitee.com/godenSpirit/mto-excel
代码可以在上面看,下面是我的一些总结

一.拆解泛型

在List集合中必须要指定一个泛型T,他是动态的,我要做的就是用反射分析这个T的属性,然后再做进一步的操作
好在C#的泛型比JAVA更强大,在运行时也保证其类型的确定,而不是JAVA的类型擦除(在运行时无法保证类型的确定性),
反射拿出一个类型的属性很简单,以所有属性都是基础类型的poco为例,

Type Target = typeof(T);
PropertyInfo[] pros = Target.getProperties();

再遍历属性拿出值即可

foreach(PropertyInfo pro in pros)
{
	Object obj = pro.getValue(集合的Element实例);
}

但以如此方法,拿出引用类型属性则会直接给那个对象不能进一步的打印,我使用一个自定义的Attribute来标记是否需要打印引用对象属性的具体值

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class ReferenceType : Attribute   //这个标记将属性标记为引用类型
    {
        //是否将引用类型再按属性拆分为多个列展示
        private bool isMultiColumn = true;

        public ReferenceType(bool isMultiColumn)
        {
            this.isMultiColumn = isMultiColumn;
        }

        public bool getIsMultiPart()
        {
            return this.isMultiColumn;
        }
    }

如此一来这则得到引用属性的属性值(比较套娃)则比较困难
但并不是不能获取

 list.Foreach(item=>{
 		PropertyInfo[] pros = typeof(item).getProperties();
		foreach(PropertyInfo property in pros)
		{
			if(property is 引用类型)
			{
				PropertyInfo[] innerPros = property.PropertyType.getProperties();
				foreach(PropertyInfo secProperty in innerPros)
				{
					//获取引用属性的属性值,在三层的循环中,不太好判断
					Object obj = secProperty.getValue(property.getValue(item));
				}
			}
			
			//正常写入Excel
		}

	});

二.不同的输出到Excel的方式

可以将引用类型输出成很多列,也要允许只在一个列里,
也要能让人忽略掉一些不想输出的属性,
这个则比上面更加简单一点

/// 
    /// 忽略制定标记的属性值
    /// 
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false,Inherited =true)]
    public class IgnoreType:Attribute
    {

        public IgnoreType()
        {

        }
    }

忽略某个属性其实就是在打印Excel的循环中跳过中间的某次循环

if (WrapperConverter.IgnoreTypePool.ContainsKey(pro.PropertyType))
{
	//一定要在循环的开头进行判断要不要忽略本次循环
		
     //如果在忽略类型中就直接Continue,开始下一轮循环
     continue;
 }
三.使用设计模式来分离关注度

虽然这个工具的代码不多,但三层循环去操作泛型,反射,标记还是有一定难度的。
使用设计模式来分散代码的功能

其中,我使用包装模式,将判断属性是否被标记的操作交给包装类,不在真正操作类上去获取标记并进行判断

/// 
    /// 这是一个基本转化器的包装类,Design By Description Mode
    /// 
    /// 
    public class WrapperConverter
    {
        //类型池,用来保存打了Attribute的标签的自定义类型
        public static Dictionary TypePool = new Dictionary();
        public static Dictionary IgnoreTypePool = new Dictionary();
        /// 
        /// taget对象,用来具体的打表
        /// 
        public BasicConverter basic = null;

        public WrapperConverter()
        {
            basic = new BasicConverter();

        }

        public IWorkbook ConvertToExcel(List list)
        {
            //在调target执行真正的方法之前,在此可以设置增强方法 advice method
            CheckAttribute(typeof(T));

            return basic.ConvertToExcel(list);
        }

        /// 
        /// (增强方法)检查泛型类型的属性中是否带有自定义的Reference的标签--check
        /// 
        /// 
        public void CheckAttribute(Type type)
        {
            PropertyInfo[] pros = type.GetProperties();

            foreach (PropertyInfo pro in pros)
            {
                //遍历获取属性中的Attribute对象
                ReferenceType refer = (ReferenceType)pro.GetCustomAttribute(typeof(ReferenceType));
                IgnoreType ignore = (IgnoreType)pro.GetCustomAttribute(typeof(IgnoreType));
                if (refer != null)
                {
                    //将打了标记的类型和标记本身放到类型池中
                    TypePool.Add(pro.PropertyType, refer);
                }
                if(ignore != null)
                {
                    IgnoreTypePool.Add(pro.PropertyType, ignore);
                }


            }
        }

        
    }

这样我就不用在检查标记了

测试:
 public class Animal
 {
     public int Id { get; set; }
     public string Name { get; set; }
     public string Category { get; set; }
     public string LivingArea { get; set; }
     public int[] testArray { get; set; }
 }
public class Person
 {
     public string id { get; set; }

     public string name { get; set; }

     [IgnoreType]
     public float tall { get; set; }

     [ReferenceType(true)]
     public Animal pet { get; set; }
 }
 static void Main(string[] args)
 {
     List list = new List()
     {
         new Person { id = "202101",name = "张三",tall = 1.7f,pet = new Animal { Id = 1,Name = "佩奇",Category="猪",LivingArea="新日暮里" } },
         new Person { id = "202102",name = "李四",tall = 1.8f,pet = new Animal { Id = 2,Name = "旺财",Category="狗",LivingArea="SomeWhere" } },
     };

     WrapperConverter wrapper = new WrapperConverter();
     //wrapper.basic = new BasicConverter();

     IWorkbook workbook = wrapper.ConvertToExcel(list);

     FileStream fileStream = new FileStream("C:/Users/ASUS/Desktop/Demo3.xls", FileMode.Create);

     workbook.Write(fileStream);

     fileStream.Close();
 }


最后,欢迎提出意见

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/693916.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号