C#学习之Reflection
1、什么是反射:
Reflection,中文翻译为反射。
这是.Net中获取运行时类型信息的方式 ,.Net的应用程序由几个部分: ‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几 个组成部分的相关信息。
反射的概述
反射的定义:审查元数据并收集关于它的类型信息的能力 。元数据(编译以后的最基本数据单 元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等。System.reflection命名 空间包含的几个类,允许你反射(解析)这些元数据表的代码。
2、反射的具体用途:
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用 Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用 ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或 GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如 pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的 方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取 或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程 序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
3、与反射相关的命名空间:
System.Reflection.Assembly
System.Reflection.MemberInfo
System.Reflection.EventInfo
System.Reflection.FieldInfo
System.Reflection.MethodBase
System.Reflection.ConstructorInfo
System.Reflection.MethodInfo
System.Reflection.PropertyInfo
System.Type
4、反射的层次模型:
注:层次间都是一对多的关系
反射的作用:
1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型
2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
应用要点:
1. 现实应用程序中很少有应用程序需要使用反射类型
2. 使用反射动态绑定需要牺牲性能
3. 有些元数据信息是不能通过反射获取的
4. 某些反射类型是专门为那些CLR开发编译器的开发使用的,所以你要意识到不是所有的反射类型都是适合每个人的。
6、反射的实际应用:
反射 appDomain 的程序集
static void Main
{
// 通过GetAssemblies 调用appDomain的所有程序集
foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies())
{
// 反射当前程序集的信息
reflector.ReflectOnAssembly(assem)
}
}
说明:调用AppDomain 对象的 GetAssemblies 方法 将返回一个由System.Reflection.Assembly元素组成的数组。
反射单个程序集
我们可以显示的调用其中的一个程序集,system.reflecton.assembly 类型提供了下面三种方法:
1. Load 方法:极力推荐的一种方法,Load 方法带有一个程序集标志并载入它,Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序基目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常。
2. LoadFrom 方法:传递一个程序集文件的路径名(包括扩展名),CLR会载入您指定的这个程序集,传递的这个参数不能包含任何关于版本号的信息,区域性,和公钥信息, 如果在指定路径找不到程序集抛出异常。
3. LoadWithPartialName:永远不要使用这个方法,因为应用程序不能确定再在载入的程序集的版本。该方法的唯一用途是帮助那些在.Net框 架的测试环节使用.net 框架提供的某种行为的客户,这个方法将最终被抛弃不用。
注意:system.AppDomain 也提供了一种Load 方法,他和Assembly的静态Load 方法不一样,AppDomain的 load 方法是一种实例方法,返回的是一个对程序集的引用,Assembly的静态Load 方发将程序集按值封装发回给发出调用的 AppDomain.尽量避免使用AppDomain的load 方法
利用反射获取类型信息
一个简单的利用反射获取类型信息的例子:
using system;
using sytem.reflection;
class reflecting
{
static void Main(string[]args)
{
reflecting reflect=new reflecting();// 定义一个新的自身类
//调用一个 reflecting.exe程序集
assembly myAssembly =assembly.loadfrom(“reflecting.exe”)
reflect.getreflectioninfo(myAssembly);// 获取反射信息
}
// 定义一个获取反射内容的方法
void getreflectioninfo(assembly myassembly)
{
type[] typearr=myassemby.Gettypes();//获取类型
foreach (type type in typearr)//针对每个类型获取详细信息
{
//获取类型的结构信息
constructorinfo[] myconstructors=type.GetConstructors;
// 获取类型的字段信息
fieldinfo[] myfields=type.GetFiedls()
//获取方法信息
MethodInfo myMethodInfo=type.GetMethods();
// 获取属性信息
propertyInfo[] myproperties=type.GetProperties
//获取事件信息
EventInfo[] Myevents=type.GetEvents;
}
}
}
其它几种获取type对象的方法:
1. System.type 参数为字符串类型,该字符串必须指定类型的完整名称(包括其命名空间)
2. System.type 提供了两个实例方法:GetNestedType,GetNestedTypes
3. Syetem.Reflection.Assembly 类型提供的实例方法是:GetType,GetTypes,GetExporedTypes
4. System.Reflection.Moudle 提供了这些实例方法:GetType,GetTypes,FindTypes
设置反射类型的成员
反射类型的成员就是反射层次模型中最下面的一层数据。我们可以通过type对象的 GetMembers 方法取得一个类型的成员。如果我们使用的是不带参数的GetMembers,它只返回该类型的公共定义的静态变量和实例成员,我们也可以通过使用带参数的 GetMembers通过参数设置来返回指定的类型成员。具体参数参考msdn 中system.reflection.bindingflags 枚举类型的详细说明。
例如:
// 设置需要返回的类型的成员内容
bindingFlags bf=bingdingFlags.DeclaredOnly|bingdingFlags.Nonpublic|BingdingFlags.Public;
foreach (MemberInfo mi int t.getmembers(bf))
{
writeline(mi.membertype) //输出指定的类型成员
}
通过反射创建类型的实例
通过反射可以获取程序集的类型,我们就可以根据获得的程序集类型来创建该类型新的实例,这也是前面提到的在运行时创建对象实现晚绑定的功能。我们可以通过下面的几个方法实现:
1. System.Activator 的CreateInstance方法。该方法返回新对象的引用。
2. System.Activator 的createInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集。
3. System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和 CreateInstraceFromAndUnwrap
4. System.type 的InvokeMember实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。
5. System.reflection.constructinfo 的Invoke实例方法
反射类型的接口
如果你想要获得一个类型继承的所有接口集合,可以调用 Type的FindInterfaces GetInterface或者 GetInterfaces。所有这些方法只能返回该类型直接继承的接口,他们不会返回从一个接口继承下来的接口。要想返回接口的基础接口必须再次调用上述方法。
反射的性能
反射时CLR要做更多的工作:校验参数,检查权限等等,速度是非常慢的。 尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可采取以下几种方式进行代替:
1.通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
2.通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
3.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些。
使用注意事项:
1、跨程序集的反射
在开发中,经常会遇到这种情况,在A.dll中需要反射B.dll中的类型,如果稍不注意,就会产生运行时错误。关于跨程序集的反射,记住两点:
(1)如果使用typeof,编译能通过,则跨程序集的反射一定可以正常运行。可以说,typeof是支持强类型的。比如
Type supType = typeof(EnterpriseServerBase.DataAccess.IDBAccesser) ;
如果当前程序集没有添加对EnterpriseServerBase.dll的引用,则编译会报错。
(2)如果使用Type.GetType,情况就复杂些,这是因为Type.GetType是非强类型的。Type.GetType的参数是一个 string,当string表示的目标类型不在当前程序集中,则运行时Type.GetType会返回null。解决的办法是:首先加载目标程序集,然后再使用Assembly.GetType方法。如
Assembly asmb = Assembly.LoadFrom("EnterpriseServerBase.dll") ;
Type supType = asmb.GetType("EnterpriseServerBase.DataAccess.IDBAccesser") ;
注意,当使用Type.GetType的时候,即使你添加了对EnterpriseServerBase.dll的引 用,Type.GetType("EnterpriseServerBase.DataAccess.IDBAccesser")也会返回null,这是因为Type.GetType只会在当前程序集中进行类型搜索。
2、反射时判断一个方法的返回类型是否为void
Type serviceType = typeof(T);
MethodInfo methodInfo = serviceType.GetMethod(methodName);
判断methodInfo.ReturnType == typeof(void)是否为true即可。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

常量也称为变量,一旦定义,其值在程序执行期间就不会改变。因此,我们可以将变量声明为引用固定值的常量。它也被称为文字。必须使用Const关键字来定义常量。语法C编程语言中使用的常量语法如下-consttypeVariableName;(or)consttype*VariableName;不同类型的常量在C编程语言中使用的不同类型的常量如下所示:整数常量-例如:1,0,34,4567浮点数常量-例如:0.0,156.89,23.456八进制和十六进制常量-例如:十六进制:0x2a,0xaa..八进制

VS代码和VisualStudioC++IntelliSense可能无法拾取库,尤其是在处理大型项目时。当我们将鼠标悬停在#Include<;wx/wx.h>;上时,我们看到了错误消息“CannotOpen源文件‘string.h’”(依赖于“wx/wx.h”),有时,自动完成功能无法响应。在这篇文章中,我们将看到如果VSCode和VSC++IntelliSense不能工作或不能提取库,你可以做些什么。为什么我的智能感知不能在C++中工作?处理大文件时,IntelliSense有时

您是否由于错误代码8C230002而无法在Xbox上购买或观看内容?一些用户在尝试购买或在其控制台上观看内容时不断收到此错误。抱歉,Xbox服务出现问题。稍后再试.有关此问题的帮助,请访问www.xbox.com/errorhelp。状态代码:8C230002这种错误代码通常是由于暂时的服务器或网络问题引起的。但是,还有可能是由于帐户的隐私设置或家长控制等其他原因,这些可能会阻止您购买或观看特定内容。修复Xbox错误代码8C230002如果您尝试在Xbox控制台上观看或购买内容时收到错误代码8C

我们以整数数组Arr[]作为输入。目标是使用递归方法在数组中找到最大和最小的元素。由于我们使用递归,我们将遍历整个数组,直到达到长度=1,然后返回A[0],这形成了基本情况。否则,将当前元素与当前最小或最大值进行比较,并通过递归更新其值以供后续元素使用。让我们看看这个的各种输入输出场景−输入 −Arr={12,67,99,76,32};输出 −数组中的最大值:99解释 &mi

5月25日消息,中国东方航空在业绩说明会上披露了关于C919客机的最新进展。据公司表示,与中国商飞签署的C919采购协议已于2021年3月正式生效,其中首架C919飞机已在2022年底交付。预计不久之后,该飞机将正式投入实际运营。东方航空将以上海为主要基地进行C919的商业运营,并计划在2022年和2023年引进总共5架C919客机。公司表示,未来的引进计划将根据实际运营情况和航线网络规划来确定。据小编了解,C919是中国具有完全自主知识产权的全球新一代单通道干线客机,符合国际通行的适航标准。该

以不同格式显示数字是学习基本编码问题之一。不同的编码概念,如条件语句和循环语句。有不同的程序中,我们使用特殊字符(如星号)来打印三角形或正方形。在本文中,我们将以螺旋形式打印数字,就像C++中的正方形一样。我们将行数n作为输入,然后从左上角开始移向右侧,然后向下,然后向左,然后向上,然后再次向右,以此类推等等。螺旋图案与数字123456724252627282982340414243309223948494431102138474645321120373635343312191817161514

根据TIOBE编程社区指数,该指数是衡量编程语言受欢迎程度的标准之一,通过收集来自全球工程师、课程、供应商和搜索引擎的数据进行评估。2024年1月TIOBE指数于近日发布,同时官方公布了2023年编程语言排名,C#荣获TIOBE2023年度编程语言,这是23年来C#首次拿下这一荣誉。TIOBE官方新闻稿称,C#已经稳居前10名长达20多年,如今它正在追赶四大语言,成为一年内涨幅最大的编程语言(+1.43%),当之无愧地获得了该奖项。排名第二的是Scratch(+0.83%)和Fortran(+0

C中的void是一个特殊的关键字,用来表示空类型,也就是指没有具体类型的数据。在C语言中,void通常用于以下三个方面。函数返回类型为void在C语言中,函数可以有不同的返回类型,例如int、float、char等。然而,如果函数不返回任何值,则可以将返回类型设为void。这意味着函数执行完毕后,并不返回具体的数值。例如:voidhelloWorld()
