反射反射,程序员的快乐+反射案例:打印和Excel导出
还是那几句话:
学无止境,精益求精
十年河东,十年河西,莫欺少年穷
学历代表你的过去,能力代表你的现在,学习代表你的将来
看过设计模式的童鞋都知道:反射反射,程序员的快乐!今天我们就利用反射来制作打印和Excel报表导出,不过在进行案例之前,我们探讨下反射的基础知识:
借用别人博客的一个举例来描述反射:
B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内脏的生理情况。这是如何做到的呢?B超是B型超声波,它可以透过肚皮通过向你体内发射B型超声波,当超声波遇到内脏壁的时候就会产生一定的“回音”反射,然后把“回音”进行处理就可以显示出内脏的情况了(我不是医生也不是声学专家,不知说得是否准确^_^)。
B超利用超声波去探索人体内部的结构,反射其实和B超差不多,只不过在这里我们是利用反射去了解类的内部构造,比如类的属性,成员,方法,接口,命名空间,类的全名等
我们在使用反射前,需要引入程序集:

引入后,我们就可以进行反射的测试了,
1、首先从反射常用的 System.Type 说起,我们可以利用 System.Type 来探测类的内部接口,比如:类的属性,方法,成员,接口等
具体的用法表现为:
Type类的属性:
Name 数据类型名
FullName 数据类型的完全限定名(包括命名空间名)
Namespace 定义数据类型的命名空间名
IsAbstract 指示该类型是否是抽象类型
IsArray 指示该类型是否是数组
IsClass 指示该类型是否是类
IsEnum 指示该类型是否是枚举
IsInterface 指示该类型是否是接口
IsPublic 指示该类型是否是公有的
IsSealed 指示该类型是否是密封类
IsValueType 指示该类型是否是值类型
Type类的方法:
GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息
GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息
GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息
GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息
GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息
GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息
GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息
可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。
根据上述的具体用法,我们作如下测试:
static void Main(string[] args)
{
//1、反射基本的类 获取属性及方法
Type type = typeof(Person);
Console.WriteLine("类型名:" + type.Name); Console.WriteLine("类全名:" + type.FullName); Console.WriteLine("命名空间名:" + type.Namespace); Console.WriteLine("程序集名:" + type.Assembly); Console.WriteLine("模块名:" + type.Module); Console.WriteLine("基类名:" + type.BaseType); Console.WriteLine("是否类:" + type.IsClass); Console.WriteLine("类的公共成员(Public):"); MemberInfo[] memberInfos = type.GetMembers();//得到所有公共成员
foreach (var item in memberInfos)
{
Console.WriteLine(string.Format("{0}:{1}", item.MemberType, item)); }
Console.WriteLine("类的公共属性(Public):");
PropertyInfo[] Propertys = type.GetProperties();
foreach (PropertyInfo fi in Propertys)
{
Console.WriteLine(fi.Name);
} Console.WriteLine("类的公共方法(Public):");
MethodInfo[] mis = type.GetMethods();
foreach (MethodInfo mi in mis)
{
Console.WriteLine(mi.ReturnType + " " + mi.Name);
} Console.WriteLine("类的公共字段(Public):");
FieldInfo[] fis = type.GetFields();
foreach (FieldInfo fi in fis)
{
Console.WriteLine(fi.Name);
} Console.ReadKey();
}
2、利用发射创建对象并调用相应的方法 (System.Reflection.Assembly):
namespace SJMS
{
class Program
{
static void Main(string[] args)
{
string Namespace = "SJMS.Robot";
Person report = (Person)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(Namespace + ".Robot", false, System.Reflection.BindingFlags.Default, null, null, null, null);
report.Speak();
Console.ReadKey();
}
} public abstract class Person
{
public string PersonType = "地球人";//字段
public string Name { get; set; }//属性+方法:get_Name 等
public int Asge { get; set; }//属性
public string Sex { get; set; }//属性
public abstract void Speak();//方法
} public class Student : Person
{
public string StudentNo { get; set; }
public override void Speak()
{
Console.WriteLine("我的名字是:" + Name);
} public string GetStudentNo()
{
return "";
}
}
} namespace SJMS.Robot
{
public class Robot : Person
{
public override void Speak()
{
Console.WriteLine("大家好:我是机器人。");
}
}
}
这里需要说明一下:

上述截图中的NameSpace是指命名空间,字符串 .Robot 是指类名,两者相加即构成: SJMS.Robot.Robot 这是一个类的全名,我们利用反射去查找这个类,如果找不到,则会异常并抛出未将对象引用到对象实例,因此在构造时,一定要仔细点。
呵呵
上述截图代码执行后,我们就创建了一个 SJMS.Robot.Robot 类的对象,这是一个机器人对象,如下:

创建了对象,调用说话的方法即可:

3、利用发射探测当前程序集 (System.Reflection.Assembly)
class Program
{
static void Main(string[] args)
{
//2、获取当前执行代码的程序集
Assembly assem = Assembly.GetExecutingAssembly(); Console.WriteLine("程序集全名:" + assem.FullName); Console.WriteLine("程序集的版本:" + assem.GetName().Version); Console.WriteLine("程序集初始位置:" + assem.CodeBase); Console.WriteLine("程序集位置:" + assem.Location); Console.WriteLine("程序集入口:" + assem.EntryPoint); Type[] types = assem.GetTypes();
Console.WriteLine("程序集下包含的类型:");
foreach (var item in types)
{ Console.WriteLine("类:" + item.Name);
}
Console.ReadKey();
}
}
执行如下:

OK,上述便是反射最常用的方法,在此我们进行一个反射的应用:
利用反射结合资源文件解读数据库字段
例如,我们有如下一张数据表:
Create table WeChat_User
(
Id int identity(1,1) not null primary key,
subscribe int,--用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
openid varchar(100) not null unique,--用户的标识,对当前公众号唯一
nickname nvarchar(50),--用户的昵称
sex int default(0),--用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
city nvarchar(50),--用户所在城市
province nvarchar(50),--用户所在省份
country nvarchar(50),--用户所在国家
U_language varchar(50),-- 用户的语言,简体中文为zh_CN
headimgurl varchar(300),--用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
subscribe_time datetime,--用户关注时间
)
接触过微信公众号开发的人员都知道,上述表描述的是微信公众号粉丝信息。
根据数据表,创建对应的Model
public class SubscribeUserModel
{
public int Id { get; set; }
public int subscribe { get; set; }
public string openid { get; set; }
public string nickname { get; set; }
public int sex { get; set; }
public string language { get; set; }
public string city { get; set; }
public string province { get; set; }
public string country { get; set; }
public string headimgurl { get; set; }
public DateTime subscribe_time { get; set; }
}
根据各属性的含义。创建对应的资源文件:

创建资源文件读取类:
public class Library
{
/// <summary>
/// 获取资源文件--根据资源文件键的名字,取出对应的值
/// </summary>
/// <param name="ResourceCode">ResourceCode</param>
/// <returns></returns>
public static string GetResourceString(string ResourceCode)
{
return WeChat_User.ResourceManager.GetString(ResourceCode);
}
}
测试代码如下:
class Program
{
static void Main(string[] args)
{
//假设数据库中目前有2个粉丝
List<SubscribeUserModel> list = new List<SubscribeUserModel>();
SubscribeUserModel Model_1 = new SubscribeUserModel()
{
Id = ,
subscribe = ,
openid = "openid_1",
nickname = "隔壁老王",
sex = ,
language = "zh_CN",
city = "苏州",
province = "江苏",
country = "中国",
headimgurl = "headimgurl_1",
subscribe_time = DateTime.Now.AddDays(-)
}; SubscribeUserModel Model_2 = new SubscribeUserModel()
{
Id = ,
subscribe = ,
openid = "openid_2",
nickname = "小磨香油",
sex = ,
language = "zh_CN",
city = "郑州",
province = "河南",
country = "中国",
headimgurl = "headimgurl_2",
subscribe_time = DateTime.Now.AddDays(-)
}; list.Add(Model_1);
list.Add(Model_2);
//
Type type = typeof(SubscribeUserModel);
MemberInfo[] Properties = type.GetProperties();//得到所有公共成员
foreach (var item in list)
{
Console.WriteLine("");
Console.WriteLine("实例" + (list.IndexOf(item) + ).ToString() + "的解析如下:"); foreach (PropertyInfo Propertie in Properties)
{ string name = Propertie.Name;
object value = Propertie.GetValue(item, null);
if (value != null)
{
Console.WriteLine(Library.GetResourceString(name) + ":" + value.ToString());
}
}
} Console.ReadKey();
}
}
输出如下:

OK。上述的简单案例就这么多,下面贴出如何利用反射来进行打印和Excel的导出,由于代码比较多,因此,提供源代码下载地址:https://download.csdn.net/download/wolongbb/10273605
@陈卧龙的博客
反射反射,程序员的快乐+反射案例:打印和Excel导出的更多相关文章
- 程序员Y先生投保案例分享
大家好,我是闲鱼君.我在2018年底搞了个副业,做了保险经纪人.保险经纪人是为用户服务的第三方机构,找经纪人买保险省钱.省力.保险一次就买对,而且还能提供后续理赔服务,具体可以看我的文章<201 ...
- C# 反射Reflection——反射反射程序员的快乐
一.什么是反射 反射Reflection:System.Reflection,是.Net Framework提供的一个帮助类库,可以读取并使用metadata. 反射是无处不在的,MVC-Asp.Ne ...
- 从程序员到CTO的Java技术路线图(我爱分享)
在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高级特性 反射.泛型. ...
- 从程序员到CTO的Java技术路线图 作者:zz563143188
在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高级特性 反射.泛型. ...
- 从程序员到CTO的Java技术路线图 (转自安卓巴士)
在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高级特性 反射.泛型. ...
- Java程序员职业生涯规划完整版:从程序员到CTO( 摘)
在技巧方面无论我们怎么学习,总感觉需要晋升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高等特性 反射.泛型. ...
- 从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析
http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...
- [转]从程序员到CTO的Java技术路线图
原文链接:http://zz563143188.iteye.com/blog/1877266 在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常 ...
- 要做Java程序员 需要知道那些技术 重点有那些
一.Java程序员 高级特性 反射.泛型.注释符.自动装箱和拆箱.枚举类.可变 参数.可变返回类型.增强循环.静态导入 ...
随机推荐
- 【BI学习笔记】在Linux上安装Wyn Enterprise商业智能报表服务器
在百度文库上找来的,放到这里,避免以后丢了. 葡萄城出品的Wyn Enterprise商业智能软件的设计器和查看视图是通过浏览器使用的,不需要安装专门的程序.Wyn Enterprise的服务器端可以 ...
- Android中使用progurad混淆代码
第一步,取消project.properties中关于progurad的注释,开启progurad,默认的配置文件会被加载进来. proguard.config=${sdk.dir}/tools/pr ...
- ::before和::after伪元素的妙用
场景: 假如有一天,你的在写一个前端项目,是关于一份点餐商家电话信息表,你啪塔啪塔地写完了,突然间项目经理跑过来找你,要求你在每一个商家的电话号码前都添加一个电话符号,来使得电话号码更直观和页面更美观 ...
- element-ui的回调函数Events的用法
做轮播的时候想用这个change回调函数,但是官方文档上竟然就只列了这么一行东西,完全没有示例代码(也可能我没找到哈) 鼓捣了半天,东拼西凑终于找到了靠谱的使用方法,其实很简单 在轮播组件上加上@ch ...
- JQuery实现1024小游戏
最近用Jqery写了一个1024小游戏,由于是第一次写小游戏,所以就选了一个基础的没什么难度游戏.具体实现如下: 首先在开发时将整个游戏分成两层(自认为),底层是游戏的数据结构以及对数据的操作,上层是 ...
- el-table表格标题换行
在做一些管理后台的项目中,表格时最常见的,当有时数据字段多时往往会用滚动条,但从用户体验角度讲,肯定需要多展示信息,那么可能需要一个单元格放多个字段,这时候表头就需要换行. 具体实现如下: // 注意 ...
- console.time和console.timeEnd用法
console.time和console.timeEnd这两个方法可以用来让WEB开发人员测量一个javascript脚本程序执行消耗的时间.随着WEB应用越来越重要,JavaScript的执行性能也 ...
- log4j2 yml
1.log4j2默认加载文件为log4j2.xml 2.要使用yml加载需添加依赖 <!-- https://mvnrepository.com/artifact/com.fasterxml.j ...
- ESP-手机--双向通信模式
1 AP 接受手机 2 STA(密码固定)连接路由器,AP接受手机 3 STA(密码灵活)连接路由器,AP接受手机 1 AP 接受手机 #include <ESP8266WiFi.h> ...
- YOLO2(1)配置安装win10+openvc2413+VS2013 简单测试官例
参考官网 https://github.com/AlexeyAB/darknet#how-to-compile-on-windows https://github.com/AlexeyAB/darkn ...