在一线编码已有多年,积累了不少非常实用的技能,最近的更新会逐步的分享出来,希望能帮助到还有一丢丢喜欢.Net的朋友,当然这些都比较适合入门选手,虽然自己已是个精通抄代码的老猿,但技术造诣仍是渣渣。

犹记得当年,自己凭借满腔热血,习得一身Java理论知识,一本《Java从入门到精通》常伴左右。初入大四后,已觉自己羽翼丰满,可以起飞,于是跃跃欲试,自信满满的外出找实习。我拿着自己精心制作的简历,上面一众“图书管理系统”、“学生成绩查询系统”、“酒店管理系统”、“出入库管理系统”等热血参与大制作。想着自己拥有如此丰厚的经历,offer定是信手拈来。

第一家:五人大公司,深藏居民楼小角落

大胡子:你知道PHP吗?

我:……我想学java

大胡子:PHP现在是最流行的语言,我们有专人带你,就看中你的好学。

我:可是我想学java

大胡子:给你一个月开1600,怎么样?

我:好(真是毫无原则的狗蛋)……

一礼拜后我离职了,他们哪里是在做开发,就是做拼接页面而已,我也只是整理资料,打扫卫生。

第二家:10人超大公司,一间公寓

小白脸:做过公司系统吗?

我:(难道我做的都是玩的吗?)做的少。

小白脸:做学生成绩查询系统时如何考虑并发?

我:……

小白脸:问了你几个问题,都是理论多,实操很少啊。

我:……

小白脸:给你个建议,别着急找工作,回去再好好学,基础不扎实么,要多做公司级系统。

我:……

第三家:15人巨头公司,居民楼

老板:我们现在愿意招学生,愿意培养,java和.net都一样,条条大路通罗马,不用过于追求语言的差别,学好了都是大牛。

我:是的是的(被一语道破心中疑虑,反正我小白一个,用什么技术栈都一样从零起步)

老板:来我们公司,我带你……

一如此门深似海,从此Java是路人。

--------以上演义都是本人真实经历改编,意在告诫各位语言无好坏,只有使用的人才有差别

我们来看下今天的主题:

听到反射,很多人应该和我一样有这么几个疑问:

1.DLL内容都了解的话,直接引用DLL不就好了吗,为什么还要反射?
2.DLL里面的内容什么都不知道的话,就算反射的话,也不知道里面的方法是干什么的啊,和直接引用DLL没区别啊?

这几个问题先不着急回答,我们继续分析下。

想要知道反射,就必须先了解一下计算机是如何运行我们写的代码的,如下图:

对于计算机来讲,它只认识01010101之类的二进制代码,人类写的高级语言(如C#、JAVA等)计算机是没法识别的,所以需要将高级语言转化为01让计算机可以识别的二进制编码,中间是有一个过程的。就拿C#来讲,VS编译器会将编写好的代码进行编译,编译后会生成exe/dll文件,.Net Core里面已经不生成exe了,都是dll。dll和exe还需要CLR/JIT的即时编译成字节码,才能最终被计算机执行。有伙伴就会问为什么要编译2次呢,先编译到dll,再编译到字节码01呢,为什么不能一次性编译成字节码呢?因为我们写的是C#语言,但是真实运行的机器有很多种,可能是32位,也可能是64位,操作系统可能是windows、linux、unix等,不同的计算机不同的操作系统识别字节码的可能是不一样的,但是从高级语言编译成exe/dll这一步是一样的。所以只要在不同运行环境的计算机上安装对应的不同的CLR/JIT,就可以运行我们同一个exe/dll了。这里就大概讲下这样一个过程,后面会有章节详细讲解程序如何被计算机执行的。现在我们先关注编译生成的exe/dll,它包含2部分,分别是中间语言IL和源数据元数据metadata。IL里面包含我们写的大量的代码,比如说方法、实体类等。元数据metadata不是我们写的代码,它是编译器在编译的时候生成的描述,它可能是把命名空间、类名、属性名记录了一下,包括特性。

讲上面程序的编译过程跟反射有什么关系呢?我们反射就是读取metadata里面的数据的,然后去使用它。

反射是.NET中的重要机制,通过反射可以得到*.exe或*.dll等程序集内部的接口、类、方法、字段、属性、特性等信息,还可以动态创建出类型实例并执行其中的方法。

一、反射的用途:

类型 作用
Assembly 定义和加载程序集,加载程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
Module 了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
ConstructorInfo 了解构造器的名称、参数、访问修饰符(如public或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
MethodInfo 了解方法的名称、返回类型、参数、访问修饰符(如public或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
FieldInfo 了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
EventInfo 了解事件的名称、事件处理程序数据类型、自定义特性、声明类型和反射类型等,并添加或移除事件处理程序。
PropertyInfo 了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,并获取或设置属性值。
ParameterInfo 了解参数的名称、数据类型、参数是输入参数还是输出参数等,以及参数在方法签名中的位置等。

二、反射实例

我们通过实际例子来看下反射的用途。

1.首先建立一个控制台程序,并添加一个类库,里面建立一个AnimalsInfo类

AnimalsInfo中定义如下属性和方法:

  1. public class AnimalsInfo
  2. {
  3. public string Type { get; set; }
  4. public int Size { get; set; }
  5. public void CommonMethod()
  6. {
  7. Console.WriteLine("我就是一个普通方法");
  8. }
  9. public void ParameterMethod(string type)
  10. {
  11. Console.WriteLine("我是带参数方法,我是" + type);
  12. }
  13.  
  14. public void OverrideMethod(int size)
  15. {
  16. Console.WriteLine($"我是重载方法,我有{size}大");
  17. }
  18. public void OverrideMethod(string name)
  19. {
  20. Console.WriteLine("我是重载方法,我叫" + name);
  21. }
  22. public void GenericityMethod<T>(T t)
  23. {
  24. Console.WriteLine("我是泛型方法方法,类型是" + typeof(T));
  25. }
  26. private void PrivateMethod()
  27. {
  28. Console.WriteLine("我是私有方法");
  29. }
  30. public static void StaticMethod()
  31. {
  32. Console.WriteLine("我是静态方法");
  33. }
  34. }

2.利用反射获取类库,属性

  1. using System;
  2. //第一步引用命名空间
  3. using System.Reflection;
  4.  
  5. namespace ReflectionTest
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
           Console.WriteLine("以下是获取类库的");
  11. //第二步,动态加载类库,一定写要获取类库的**绝对路径**
  12. Assembly assembly = Assembly.LoadFile(@"C:\Users\XA-BAU-Lyvin\source\repos\ReflectionTest\ReflectionTest.Model\bin\Debug\netcoreapp3.1\ReflectionTest.Model.dll");
  13. //第三步,动态获取类型,写类库的名称和类的名称
  14. Type type = assembly.GetType("ReflectionTest.Model.AnimalsInfo");
  15. Console.WriteLine(type.Name);

        Console.WriteLine("以下是获取属性的");
        //遍历类型的属性集合
        foreach (var item in type.GetProperties())
        {
        Console.WriteLine("字段名:"+ item.Name + ",类型:" + item.PropertyType);
        }

  1. }
  2. }
  3. }

 3.通过反射获取方法

  • 所有的方法都要指定要获取的方法名称
  • 创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
  • 私有方法不一样,一定有看清楚,它指明是父类的私有方法
  1. static void Main(string[] args)
  2. {
  3. Console.WriteLine("以下是获取类库的");
  4. //第二步,动态加载类库,一定写要获取类库的**绝对路径**
  5. Assembly assembly = Assembly.LoadFile(@"C:\Users\XA-BAU-Lyvin\source\repos\ReflectionTest\ReflectionTest.Model\bin\Debug\netcoreapp3.1\ReflectionTest.Model.dll");
  6. //第三步,动态获取类型,写类库的名称和类的名称
  7. Type type = assembly.GetType("ReflectionTest.Model.AnimalsInfo");
  8. Console.WriteLine(type.Name);
  9.  
  10. Console.WriteLine("以下是获取属性的");
  11. //遍历类型的属性集合
  12. foreach (var item in type.GetProperties())
  13. {
  14. Console.WriteLine("字段名:"+ item.Name + ",类型:" + item.PropertyType);
  15. }
  16.  
  17. Console.WriteLine("==============普通方法==================");
  18. //创建一个符合类型的对象
  19. object oAnimal = Activator.CreateInstance(type);
  20. //***所有的方法都要指定要获取的方法名称
  21. MethodInfo commonMethod = type.GetMethod("CommonMethod");
  22. //创建方法,第一个参数,对象,第二个参数,没有则为空
  23. commonMethod.Invoke(oAnimal, null);
  24.  
  25. Console.WriteLine("==============带参数的方法==================");
  26. MethodInfo parameterMethod = type.GetMethod("ParameterMethod");
  27. //创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
  28. parameterMethod.Invoke(oAnimal, new object[] { "狗狗" });
  29.  
  30. Console.WriteLine("==============重载方法int参数==================");
  31. MethodInfo overrideMethodInt = type.GetMethod("OverrideMethod", new Type[] { typeof(int) });
  32. overrideMethodInt.Invoke(oAnimal, new object[] { 18 });
  33.  
  34. Console.WriteLine("==============重载方法string参数==================");
  35. MethodInfo overrideMethodStrint = type.GetMethod("OverrideMethod", new Type[] { typeof(string) });
  36. overrideMethodStrint.Invoke(oAnimal, new object[] { "喵喵" });
  37.  
  38. Console.WriteLine("==============泛型方法==================");
  39. MethodInfo genericityMethod = type.GetMethod("GenericityMethod").MakeGenericMethod(new Type[] { typeof(int) });
  40. genericityMethod.Invoke(oAnimal, new object[] { 45 });
  41.  
  42. Console.WriteLine("==============私有方法==================");
  43. //指定要获取的方法名称,指明是父类的私有方法
  44. MethodInfo privateMethod = type.GetMethod("PrivateMethod", BindingFlags.Instance | BindingFlags.NonPublic);
  45. privateMethod.Invoke(oAnimal, null);
  46.  
  47. Console.WriteLine("==============静态方法=================");
  48. MethodInfo staticMethod = type.GetMethod("StaticMethod");
  49. staticMethod.Invoke(null, null);
  50. }

 三、总结

所有的反射应用方法都已经讲完了,看完以后感觉其实也没有什么神秘的,很简单对不对?

当然,还有个问题要留给大家继续讨论了:如果通过反射还可以访问私有方法,那么设置私有方法的意义在哪呢?是否和私有类型的设计初衷违背了?

首发自:【程序员不帅哥 】公众号

原文链接:https://mp.weixin.qq.com/s/LCPLjBmmbJwXBDWdi3SU1g

扫码关注,更多精彩内容及时获取,一起提高,一起加油

C#扫盲篇(一):反射机制--情真意切的说的更多相关文章

  1. 文末送书四本 | 这篇Java反射机制太经典!不看后悔!

    先看再点赞,给自己一点思考的时间,如果对自己有帮助,微信搜索[程序职场]关注这个执着的职场程序员. 价值:Java技能,面试经验指导,简历优化,职场规划指导,技能提升方法,讲不完的职场故事,个人成长经 ...

  2. javaSE高级篇4 — 反射机制( 含类加载器 ) — 更新完毕

    反射机制 1.反射机制是什么?----英文单词是:reflect.在java.lang包下---这才是java最牛逼的技术 首先提前知道一句话----在java中,有了对象,于是有了类,那么有了类之后 ...

  3. C#扫盲篇(三):Action和Func委托--实话实说

    一.基础定义 老王想找老张的老婆出去耍,但是一看,老张还在厨房煮饭.于是老王就对老张隔壁的淑芬说:"等下老张吃完饭出去喝茶,你就把前门晒的苞谷收了,老张从左门出,你就收右边的苞谷,我就知道从 ...

  4. C#扫盲篇(四):.NET Core 的异步编程-只讲干货(async,await,Task)

    关于async,await,task的用法和解释这里就不要说明了,网上一查一大堆.至于为啥还要写这篇文章,主要是其他文章水分太多,不适合新手学习和理解.以下内容纯属个人理解,如果有误,请高手指正.本文 ...

  5. Java 反射机制[Method反射]

    Java 反射机制[Method反射] 接着上一篇Java 反射机制[Field反射],通过调用Person类的setName方法将obj的name字段的Value设置为"callPerso ...

  6. 【Java入门提高篇】Day13 Java中的反射机制

    前一段时间一直忙,所以没什么时间写博客,拖了这么久,也该更新更新了.最近看到各种知识付费的推出,感觉是好事,也是坏事,好事是对知识沉淀的认可与推动,坏事是感觉很多人忙于把自己的知识变现,相对的在沉淀上 ...

  7. Httpd服务入门知识-http协议版本,工作机制及http服务器应用扫盲篇

    Httpd服务入门知识-http协议版本,工作机制及http服务器应用扫盲篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Internet与中国 Internet最早来源于美 ...

  8. Java高级特性——反射机制(第二篇)

    在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...

  9. 11.Java反射机制 哦对了,前面的序号来自随笔关于编程之路的思索第一篇

    基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于J ...

随机推荐

  1. Jenkins Job间传递参数的一种方法

    场景: Jenkins 中可以建多个Job,一般是主编译Job,多个子Job. 子Job要用主Job中的版本号,编译号. 1)  在主Job里面添加脚本命令: echo set MainVersion ...

  2. javascript中 fn() 和 return fn() 的区别

    在js中用return和不用return,输出结果有的时候傻傻搞不清,之前在网上看到个例子挺经典,不过讲的不清楚,上例子: var i = 0; function fn(){    i++;   if ...

  3. jxl导出excel小demo

    1.首先在pom文件加入jar包 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <art ...

  4. 如何实现OSM地图本地发布并自定义配图

    目录 1.缘起 2.准备环境 2.1.安装linux系统 2.2.安装docker 2.3.安装Docker Compose 2.4.安装git 3.发布地图 3.1.拉取代码 3.2.测试网络 3. ...

  5. 题解-Cats Transport

    题解-Cats Transport Cats Transport 有 \(n\) 个山丘,\(m\) 只猫子,\(p\) 只铲屎官.第 \(i-1\) 个山丘到第 \(i\) 个山丘的距离是 \(d_ ...

  6. 第一章、Docker 简介

    笔记内容来自:第一本Docker书 [澳] James Turnbull 著 李兆海 刘斌 巨震 ​ Docker 是一个能够把开发的应用程序自动部署到容器的开源引擎.(由Docker 公司,前dot ...

  7. 使用OpenSSL自建一个HTTPS服务

    1. 理论知识 1.1 什么是https 传统的 HTTP 协议以明文方式进行通信,不提供任何方式的数据加密,很容易被中间攻击者破解通信内容或者伪装成服务器与客户端通信,在安全性上存在很大问题. HT ...

  8. Unity 保存游戏,读取游戏,退出游戏

    1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using System. ...

  9. Hive JDBC执行load时无法从本地加载数据

    通过hive-jdcv连接hive server,在应用服务端执行以下命令,报错:Hiver Server节点上找不到data.txt load data local inpath '/home/dw ...

  10. 关于CAS中的ABA问题存在的隐患

    一开始觉得ABA问题确实是个问题,但是具体场景是什么呢,虽然过程改了,但是结果一样,取的值也一样 不明所以,不过呢,这里也有一个小的demo可以说明一下 该例子通过AtomicReference判断对 ...