• 反射反射,程序员的快乐+反射案例:打印和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();
            }
    View Code

    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 "081309207";
            }
        }
    }
    
    namespace SJMS.Robot
    {
        public class Robot : Person
        {
            public override void Speak()
            {
                Console.WriteLine("大家好:我是机器人。");
            }
        }
    }
    View Code

    这里需要说明一下:

    上述截图中的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();
            }
        }
    View Code

    执行如下:

    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 = 1,
                    subscribe = 0,
                    openid = "openid_1",
                    nickname = "隔壁老王",
                    sex = 1,
                    language = "zh_CN",
                    city = "苏州",
                    province = "江苏",
                    country = "中国",
                    headimgurl = "headimgurl_1",
                    subscribe_time = DateTime.Now.AddDays(-1)
                };
    
                SubscribeUserModel Model_2 = new SubscribeUserModel()
                {
                    Id = 2,
                    subscribe = 0,
                    openid = "openid_2",
                    nickname = "小磨香油",
                    sex = 1,
                    language = "zh_CN",
                    city = "郑州",
                    province = "河南",
                    country = "中国",
                    headimgurl = "headimgurl_2",
                    subscribe_time = DateTime.Now.AddDays(-1)
                };
    
                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) + 1).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

    @陈卧龙的博客

  • 相关阅读:
    (模板)高斯消元法模板
    poj1797(dijstra变形,求最小边的最大值)
    poj2253(floyd变形)
    (模板)poj2387(dijkstra+优先队列优化模板题)
    poj1915(双向bfs)
    poj3977(折半枚举+二分查找)
    uva11624 Fire! (bfs预处理)
    codeforces#1152C. Neko does Maths(最小公倍数)
    codeforces#1154F. Shovels Shop (dp)
    codeforces#1136E. Nastya Hasn't Written a Legend(二分+线段树)
  • 原文地址:https://www.cnblogs.com/chenwolong/p/Reflection.html
Copyright © 2020-2023  润新知