C#秘密武器之反射——基础篇

先来一段有用的反射代码

namespace Calculator 
{ public interface Iwel { String Print(); } 
}  namespace Calculator 
{ public class Arithmetic:Iwel { /// <summary> /// 没有带参数的构造函数 /// </summary> public Arithmetic() {} public Arithmetic(int num1, int num2) { _num1 = num1; _num2 = num2; } private int _num1; public int Num1 { get { return _num1; } set { _num1 = value; } } private int _num2; public int Num2 { get { return _num2; } set { _num2 = value; } } public String Add(int num1, int num2) { Console.WriteLine("{0}+{1}={2}", num1, num2, num1 + num2); return "Add(int num1,int num2)方法是一个公有的带参数的方法"; } private string Add() { return "Add()方法是一个私有的不传参数的方法"; } private void Subtration(int num1, int num2) { Console.WriteLine("{0}-{1}={2}+Subtration(int num1,int num2)" + "方法是一个私有的带有参数的方法 ",num1,num2,num1-num2); } public static void Multiplication(int num1, int num2) { Console.WriteLine("{0}*{1}={2} Multiplication(int num1,int num2)"+"是一个公有的带参数的静态方法",num1,num2,num1+num2); } private static void Multiplication() { Console.WriteLine("Multiplication()是一个公有的带参数的静态方法"); } public String Writ() { return "Writ() 是一个公有的不带参数的方法"; } #region Iwel 成员 public string Print() { return "欢迎您使用接口!"; } #endregion } 
} using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; namespace BassLib 
{ class Program { delegate void TestDelegate(int num1, int num2); static void Main(string[] args) { Assembly assembly = Assembly.Load("Calculator");//加载程序集 Console.WriteLine("得到Calculator.dll中的所有类"); Console.WriteLine("***********************************"); foreach (Type myType in assembly.GetTypes()) { //得到Calculator.dll中所有的类 Console.WriteLine(myType.Name + "是Calculator命中空间下的类"); } Console.WriteLine(" +++++++++++++++++++++++++++++++++++++"); Console.WriteLine("得到Calculator.dll中的模块集"); Module[] modules = assembly.GetModules();//得到Calculator.dll中的模块集合 foreach (Module module in modules) { Console.WriteLine(module.Name + "是Calculator中的一个模块 "); } Console.WriteLine("*********************************************"); Console.WriteLine(""); Type type = typeof(Calculator.Arithmetic);//得到具体的类型 Console.WriteLine("具体的类型是" + type.Name); Console.WriteLine(" {0}是不是public类型:{1}", type, type.IsPublic); Console.WriteLine("{0}是不是private类型:{1}", type, type.IsNotPublic); Console.WriteLine("*********************************************"); Console.WriteLine(""); PropertyInfo[] memberInfo = type.GetProperties();//得到类中的属性 foreach (PropertyInfo var in memberInfo) { Console.WriteLine(type + "类的属性有" + var.Name); } Console.WriteLine("**********************************************"); Console.WriteLine(""); Type[] t = type.GetInterfaces();//得到接口 foreach (Type var in t) { Console.WriteLine(var.Name + "是Calculator.dll中的接口"); } Console.WriteLine("*****************************************"); Console.WriteLine(""); Console.WriteLine("方法的返回类型,方法传参的类型"); //查找私有的方法 MethodInfo[] method = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic); foreach (MemberInfo var in method) { Console.WriteLine("私有方法: 方法名 ={0} 方法的信息={1}", var.Name, var); } //查找公有方法 MethodInfo[] methodpublic = type.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo var in methodpublic) { Console.WriteLine("公有方法:方法名={0} 方法的信息={1}", var.Name, var); } //查找公有的静态方法 MethodInfo[] mathodstatic = type.GetMethods(BindingFlags.Public | BindingFlags.Static); foreach (MethodInfo var in mathodstatic) { Console.WriteLine("公有静态方法: 方法名={0} 方法的信息 ={1}", var.Name, var); } //查找私有静态方法 MethodInfo[] methodprivartstatic = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static); foreach (MethodInfo var in methodprivartstatic) { Console.WriteLine("私有静态方法: 方法名={0} 方法的信息={1}", var.Name, var); } Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++"); Console.WriteLine("这是一个构造方法的形式 "); ConstructorInfo[] con = type.GetConstructors();//获得构造函数的形式 foreach (ConstructorInfo var in con) { Console.WriteLine(var); } Console.WriteLine("_________________________________"); object obj = Activator.CreateInstance(type, null);//创建了一个不带参数的实例 //公有非静态带参数和返回参数的方法的调用它 MethodInfo men1 = type.GetMethod("Add"); Console.WriteLine("调用{0}方法 ", men1); object[] nums1 = { 5, 4 };//参数 
             Console.WriteLine(men1.Invoke(obj, nums1)); Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); //私有的非静态方法的调用 MethodInfo men2 = type.GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic); Console.WriteLine(men2.Invoke(obj, null)); Console.WriteLine("**********************************"); //公有的静态带参数的方法的调用 MethodInfo men3 = type.GetMethod("Multiplication", BindingFlags.Public | BindingFlags.Static); object[] nums2 = { 5, 6 }; men3.Invoke(null, nums2); Console.WriteLine("*****************"); //私有的静态的 MethodInfo men4 = type.GetMethod("Multiplication", BindingFlags.NonPublic | BindingFlags.Static); men4.Invoke(null, null); Console.WriteLine("************************"); //动态创建一个委托 Console.WriteLine("动态创建委托"); TestDelegate dele = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "Subtration"); dele(9, 3); } } 
} 
View Code

反射的几种基本类型

1、System.Reflection.Assembly类

     通过Assembly可以动态加载程序集,并查看程序集的内部信息,其中最常用的就是Load()这个方法。

     Assembly assembly=Assembly.Load("MyAssembly");

     利用Assembly的object CreateInstance(string) 方法可以反射创建一个对象,参数0为类名。

2、System.Type类

     Type是最常用到的类,通过Type可以得到一个类的内部信息,也可以通过它反射创建一个对象。一般有三个常用的方法可得到Type对象。

  1. 利用typeof() 得到Type对象

    Type type=typeof(Example);

  2. 利用System.Object.GetType() 得到Type对象

    Example example=new Example();

    Type type=example.GetType();

  3. 利用System.Type.GetType() 得到Type对象

    Type type=Type.GetType("MyAssembly.Example",false,true);

    注意参数0是类名,参数1表示若找不到对应类时是否抛出异常,参数1表示类名是否区分大小写

   例子:

   我们最常见的是利用反射与Activator结合来创建对象:

Assembly assembly= Assembly.Load("MyAssembly");
Type type=assembly.GetType("Example");
object obj=Activator.CreateInstance(type);

3、反射方法

    1.通过 System.Reflection.MethodInfo能查找到类里面的方法

    代码:

Type type=typeof(Example);
MethodInfo[] listMethodInfo=type.GetMethods();
foreach(MethodInfo methodInfo in listMethodInfo)
Cosole.WriteLine("Method name is "+methodInfo.Name);

    2.我们也能通过反射方法执行类里面的方法

   代码:

Assembly assembly= Assembly.Load("MyAssembly");
Type type=assembly.GetType("Example");
object obj=Activator.CreateInstance(type);
MethodInfo methodInfo=type.GetMethod("Hello World");  //根据方法名获取MethodInfo对象
methodInfo.Invoke(obj,null);  //参数1类型为object[],代表Hello World方法的对应参数,输入值为null代表没有参数

4、反射属性

   1.通过 System.Reflection.PropertyInfo 能查找到类里面的属性

     常用的方法有GetValue(object,object[]) 获取属性值和 SetValue(object,object,object[]) 设置属性值

   代码:

Type type=typeof(Example);
PropertyInfo[] listPropertyInfo=type.GetProperties();
foreach(PropertyInfo propertyInfo in listPropertyInfo)
Cosole.WriteLine("Property name is "+ propertyInfo.Name);

   2.我们也可以通过以下方法设置或者获取一个对象的属性值

   代码:

Assembly assembly=Assembly.Load("MyAssembly");
Type type=assembly.GetType("Example");
object obj=Activator.CreateInstance(type);
PropertyInfo propertyInfo=obj.GetProperty("Name");    //获取Name属性对象
var name=propertyInfo.GetValue(obj,null);            //获取Name属性的值
PropertyInfo propertyInfo2=obj.GetProperty("Age");    //获取Age属性对象
propertyInfo2.SetValue(obj,34,null);                  //把Age属性设置为34

5、反射字段

    通过 System.Reflection.FieldInfo 能查找到类里面的字段

    它包括有两个常用方法SetValue(object ,object )和GetValue(object)  因为使用方法与反射属性非常相似,在此不再多作介绍

6、反射特性

   通过System.Reflection.MemberInfo的GetCustomAttributes(Type,bool)就可反射出一个类里面的特性,以下例子可以反射出一个类的所有特性

   代码:

Type type=typeof("Example");
object[] typeAttributes=type.GetCustomAttributes(false);       //获取Example类的特性
foreach(object attribute in typeAttributes)
Console.WriteLine("Attributes description is "+attribute.ToString());

   通过下面例子,可以获取Example类Name属性的所有特性

   代码:

public class Example{[DataMemberAttribute]publics string Name{get;set;}..................}Type type = typeof(Example);        PropertyInfo propertyInfo=type.GetProperty("Name");    //获取Example类的Name属性foreach (object attribute in propertyInfo.GetCustomAttributes(false))        //遍历Name属性的所有特性Console.WriteLine(“Property attribute: "+attribute.ToString());

7、反射成员

我们先考虑一下对于一个类型Type,可能会包含什么类型,常见的有字段、属性、方法、构造函数、接口、嵌套类型等。MemberInfo 类代表着 Type的成员类型,值得注意的是Type类本身又继承自MemberInfo类,理解起来并不困难,因为一个类型经常也是另一类型的成员。Type类提供 GetMembers()、GetMember()、FindMember()等方法用于获取某个成员类型。

我们再添加一个方法 MemberExplore(),来查看一个类型的所有成员类型。

namespace Demo
{
    class SimpleExplore
    {
        static void Main(string[] args)
        {
            MemberExplore(typeof(DemoClass));
        }
 
        public static void MemberExplore(Type t)
        {
            StringBuilder sb = new StringBuilder();
            MemberInfo[] memberInfo = t.GetMembers();
            sb.Append("查看类型 " + t.Name + "的成员信息:\n");
            foreach (MemberInfo mi in memberInfo)
            {
                sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "\n");
            }
            Console.WriteLine(sb.ToString());
        }
    }
}

产生的输出如下:

image

我们使用了GetMembers()方法获取了成员信息的一个数组,然后遍历了数组,打印了成员的名称和类型。如同我们所知道的:Name属性在编译后成为了get_Name()和set_Name()两个独立的方法;myEvent事件的注册(+=)和取消注册(-=)分别成为了add_myEvent()和remove_myEvent方法。同时,我们发现私有(private)字段name 没有被打印出来,另外,基类System.Object的成员GetType()和Equals()也被打印了出来。

有的时候,我们可能不希望查看基类的成员,也可能希望查看私有的成员,此时可以使用GetMembers()的重载方法,传入BindingFlags 位标记参数来完成。BindingFlags位标记对如何获取成员的方式进行控制(也可以控制如何创建对象实例,后面会说明)。对于本例,如果我们想获取所有的公有、私有、静态、实例成员,那么只需要这样修改GetMembers()方法就可以了。

public static void MemberExplore(Type t)
        {
            StringBuilder sb = new StringBuilder();
            //MemberInfo[] memberInfo = t.GetMembers();
            MemberInfo[] memberInfo = t.GetMembers(BindingFlags.Public | BindingFlags.Static
                | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            sb.Append("查看类型 " + t.Name + "的成员信息:\n");
            foreach (MemberInfo mi in memberInfo)
            {
                sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "\n");
            }
            Console.WriteLine(sb.ToString());
        }

此时的输出如下:

image

可以看到,继承自基类 System.Object 的方法都被过滤掉了,同时,打印出了私有的 name, myEvent 等字段。

现在如果我们想要获取所有的方法(Method),那么我们可以使用 Type类的FindMembers()方法:

public static void MemberExplore(Type t)
        {
            StringBuilder sb = new StringBuilder();
 
            //MemberInfo[] memberInfo = t.GetMembers();
 
            //MemberInfo[] memberInfo = t.GetMembers(BindingFlags.Public | BindingFlags.Static
            //    | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
 
            MemberInfo[] memberInfo = t.FindMembers(MemberTypes.Method, // 说明查找的成员类型为 Method 
                                    BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic
                                    | BindingFlags.Instance | BindingFlags.DeclaredOnly, Type.FilterName, "*");
 
            sb.Append("查看类型 " + t.Name + "的成员信息:\n");
            foreach (MemberInfo mi in memberInfo)
            {
                sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "\n");
            }
            Console.WriteLine(sb.ToString());
        }

Type.FilterName 返回一个MemberFilter类型的委托,它说明按照方法名称进行过滤,最后一个参数“*”,说明返回所有名称(如果使用“Get*”,则会返回所有以Get开头的方法)。

现在的输出如下:

image

MemberInfo 类有两个属性值得注意,一个是DeclaringType,一个是 ReflectedType,返回的都是Type类型。DeclaredType 返回的是声明该成员的类型。比如说,回顾我们之前的一段代码:

MemberInfo[] members = typeof(DemoClass).GetMembers();

它将返回所有的公有成员,包括继承自基类的Equals()等方法,对于Equals()方法来说,它的 DeclaringType 返回的是相当于 typeof(Object) 的类型实例,因为它是在 System.Object中被定义的;而它的ReflectedType 返回的则是相当于 typeof(DemoClass) 类型实例,因为它是通过 DemoClass 的类型实例被获取的。

 

转载于:https://www.cnblogs.com/WeiGe/p/4202626.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python社区版可以用库么_应用Python,你不但能够得到出色的小区适用和普遍的库集...

哪样计算机语言最好是&#xff1f;这个问题很有可能始终不容易找答案。萝卜青菜&#xff0c;各有所好&#xff0c;AI技术工程师和生物学家能够依据新项目必须&#xff0c;从诸多计算机语言中挑选最合适自身的。选Python還是选Java?2020年&#xff0c;顶级程序猿最应当把握的7种…

Python3 etree, requests库抓取bt

bt种子抓取1. 抓取你想要的数据2. 爬取bt种子3. 抓取磁力链迷上了追番.. . bt种子xunlei来解决。 推荐一个网站https://mikanani.me。可以搜索你想要的动漫… 以bt的形式下载&#xff0c;或者复制磁力链。 1. 抓取你想要的数据 需要了解requests, etree库&#xff0c;etree用…

ecshop各个文件夹作用

Images文件夹&#xff1a;这个文件夹下有子文件夹&#xff0c;在这些子文件夹下面存放着当前网站商品的原始图片和缩略图。这些子文件夹命名有规律的&#xff0c;它们的文件名是它们目录下商品加入 的年月份。也就是说在同一个月份加入的商品&#xff0c;它们的图片是在同一个文…

unity2018关联不到vs_现实VS真爱:远嫁的幸福和悲哀

陆拾一 LUSHIYI《现实VS真爱&#xff1a;远嫁的幸福和悲哀》Part.1你有过远嫁的犹豫或者经历吗&#xff1f;关于这个话题&#xff0c;我从未写过。今天借着一封读者的来信&#xff0c;与大家聊一聊。拾一&#xff0c;你好。我跟男朋友在一起两年了&#xff0c;现在到了谈婚论嫁…

dubbo使用nacos作为注册中心

spring-cloud nacos dubbodubbo接口服务提供者消费者&#xff0c;要订阅对应的服务&#xff0c;订阅提供者使用openFeign以http为协议进行rest调用。而dubbo是tcpport&#xff0c;使用tcp协议的。 版本说明 dubbo : 2.7.8 spring-cloud-alibaba: 2.1.4.RELEASE spring-cloud:…

vim下php文件中自动缩排html代码

问题&#xff1a;vim下怎样在php文件中通过 命令自动缩排html代码&#xff1f;解决&#xff1a;1、先说下html自动缩排 我的vim是7.4版本&#xff0c;已经包含了html.vim之类的缩排插件&#xff0c;但是缩排的时候<body> <head> 没有进行缩排 在.vimrc中加入如下代…

lgg8配置_LGG8XThinQ参数配置-LG G8X ThinQ详细性能评测

LG G8X ThinQ是一款全新发布的机型&#xff0c;这款手机和iPhone12一样不赠送充电器&#xff0c;那么这款手机的参数配置是什么&#xff1f;有哪些值得入手的地方&#xff1f;小编为大家带来最新的手机性能评测&#xff0c;快来看看吧。一、参数配置手机型号LG G8X ThinQ手机屏…

关于go指针在方法or函数中这件事

title1. go中的指针2. 函数中的指针3. 方法中的指针1. go中的指针 使用 *类型 声明指针… 使用*变量名获取指针的值… 使用 &p 获取指针的内存地址… fmt.Println(" 指针复习 ")// 声明指针avar a *intb : 1// 获取到b的内存地址.. 指向ba &bfmt.Println(a…

前端学习(1331):mongoose第三方模块

const mongoose require(mongoose); mongoose.connect(mongodb://localhost/playground, { useUnifiedTopology: true }).then(() > console.log(数据库连接成功)).catch(err > console.log(err, 数据库连接失败)) 运行结果

MySQL在大型网站的应用架构演变

http://www.csdn.net/article/2014-06-10/2820160 -- 原文地址 转载于:https://www.cnblogs.com/thrillerz/p/4215150.html

ikbc机械键盘打字出现重复_双十一机械键盘优惠清单,阿米洛/ikbc/吉利鸭/杜咖/美商海盗船/雷神/Filco机械键盘推荐...

这次为大家带来的是一篇双十一机械键盘的优惠汇总清单&#xff0c;其中杜咖的优惠力度较大&#xff0c;高斯的性价比很高&#xff0c;然后阿米洛则推出了好几款双十一限定款&#xff0c;我们一起来看看吧~TOP1、罗技&#xff08;Logitech&#xff09;K835原价&#xff1a;369元…

前端学习(1333):mongodb增

const mongoose require(mongoose); mongoose.connect(mongodb://localhost/playground, { useUnifiedTopology: true }).then(() > console.log(数据库连接成功)).catch(err > console.log(err, 数据库连接失败))//创建集合规则 const courseSchema new mongoose.Sche…

Exception in thread “main“ java.lang.IllegalStateException: Duplicate key xxx

debug..hah… 这个错误是使用stream流把list收集成map搞的&#xff0c;原因是map的key是唯一的&#xff0c;如果不唯一就抛出了这个异常。 下面是异常代码 import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors;/*…

Http方法:Get请求与Post请求的区别

Get是向服务器发索取数据的一种请求&#xff0c;而Post是向服务器提交数据的一种请求Get是获取信息&#xff0c;而不是修改信息&#xff0c;类似数据库查询功能一样&#xff0c;数据不会被修改Get请求的参数会跟在url后进行传递&#xff0c;请求的数据会附在URL之后&#xff0c…

前端学习(1332):mongodb安装

一、安装 双击安装文件&#xff0c;然后安装指引点击下一步 ​​ 选择【Custom】安装类型 ​​ 将程序安装到D盘MongoDB目录下&#xff08;如果切换了目录&#xff0c;记得对应调整monggo.bat下面的路径&#xff09; ​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​ ​​…

华为手机什么时候更新鸿蒙系统_华为鸿蒙系统什么时候能超过iOS、安卓?任正非表态了...

众所周知&#xff0c;自从去年8月份华为高调发布了鸿蒙系统之后&#xff0c;网友们每时每刻都在盼望着鸿蒙系统能够取代安卓&#xff0c;成为华为手机使用的操作系统。甚至还有人觉得以华为的能力&#xff0c;鸿蒙一出&#xff0c;能够迅速超过苹果的iOS和安卓系统。可惜原来余…

分布式下的session问题

分布式下的session在分布式项目下项目中使用在分布式项目下 session是一种会话状态&#xff0c;是储存在服务器上的&#xff0c;可以区分每个用户。浏览器会保存着对应的信息。浏览器保存的叫cookie。用户访问&#xff0c;浏览器会带上cookie让服务器识别。 如果是单体项目&a…