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即可。
分享到:
相关推荐
在C#编程语言中,反射(Reflection)是一个强大的工具,它允许程序在运行时检查自身的行为,包括类、接口、属性、方法等元数据信息,并能够动态地创建对象和调用方法。这篇压缩包文件提供了关于C#反射的实践示例,...
在.NET开发环境中,C#语言提供了强大的特性,使得开发者能够构建灵活、可配置且可扩展的应用程序。...在DBIOC20200709这个压缩包文件中,可能包含了实现这些功能的源代码和示例,可以进一步学习和研究。
using System.Reflection; class ThisClass { int firstValue, secondValue; public int sum() { return firstValue + secondValue; } public void assign(int a, int b) { firstValue = a; secondValue ...
在C#编程语言中,了解这些基础概念对于深入学习至关重要。让我们逐一解析这些知识点: 1. **静态变量和非静态变量的区别**: 静态变量属于类,不依赖于类的实例,所有实例共享同一静态变量。非静态变量(实例变量...
#学习的101个经典例子,例子个个经典,涵盖C#的方方面面,带有说详尽的注释 Advanced - Multithreading - How-To Async Calls Advanced - Remoting - How-To TCP Remoting Advanced - Serialization - How-To ...
这篇学习笔记将带你深入了解C#反射的基础知识,帮助你掌握这一关键技能。 1. **程序集(Assembly)**:程序集是.NET应用程序的基本部署和版本控制单位,包含了元数据和IL(中间语言)代码。你可以通过`System....
本教程集合了我工作和学习过程中积累的C#各种知识点,旨在帮助你深入理解和掌握C#的基础及高级特性。 1. **C#基础知识** - **变量与数据类型**:包括基本的数据类型(如int, string, bool等)以及引用类型。理解...
4. **自定义实现**:C#本身并不直接支持AOP,但开发者可以通过反射、动态代理(如System.Reflection.Emit或Castle.DynamicProxy)等方式来自行实现。这种方式虽然复杂,但能提供更大的灵活性。 在"C# AOP学习DEMO...
C#基类库,也称为.NET Framework类库或BCL(Base Class Library),是Microsoft .NET...而这个“C#基类库大全”压缩包,很可能是对这些类库的详细文档、示例代码或者教学材料的集合,对于学习和参考具有极高的价值。
在C#中,可以使用接口或继承来创建动态代理,如System.Reflection.Emit命名空间下的动态类型生成。 五、装饰器模式(Decorator) 装饰器模式允许向一个对象添加新的行为或责任,而不必修改其原始代码。C#中,通过...
再者,C#调试助手可能使用了反射(Reflection)来动态地获取和操作类型、方法、属性等信息,这对于在运行时分析代码的行为非常有帮助。`Type`、`MethodInfo`、`PropertyInfo`等都是反射相关的类,它们在源码中会频繁...
C#的Assembly和Reflection特性使得动态加载和管理插件变得简单。 10. **错误处理和调试**:C#的异常处理机制和Visual Studio的强大调试工具,有助于定位和修复代码中的错误。 在LISCADA.rar这个压缩包中,可能包含...
本压缩包“C# 源码(很多的源码)”提供了丰富的C#代码示例,涵盖了多个关键知识点,包括反射、接口、套接字(socket)等,对于初学者和进阶者都是极好的学习资源。 首先,让我们深入了解一下这些关键词所代表的C#...
1. 加载DLL文件:通过`System.Reflection.Assembly.LoadFile`方法加载位于指定路径的`TestReflect.dll`。 2. 获取类型信息:使用`Assembly.GetType`方法获取`ReflectTest`类的`Type`对象。 3. 创建实例:通过`...
首先,**平移(Translation)**是图像处理中最基础的操作之一,它涉及到图像在二维空间中的位置移动。在C#中,可以通过矩阵运算来实现图像的平移。假设我们有一个图像坐标(x, y),平移量为(dx, dy),那么新的坐标(x'...
2. **动态加载**:C#的`Assembly`类和`Reflection`机制允许程序在运行时加载和使用未在编译时知悉的插件。这通常涉及到使用`Assembly.Load()`加载DLL文件,然后通过反射查找并实例化实现所需接口的类型。 3. **插件...
### C#学习笔记知识点梳理 #### C#中关键字的小提示 C#作为一种强类型的语言,对关键字有着严格的规范。为了防止命名冲突,C#不允许使用关键字作为标识符。但是,在某些特殊情况下,如果确实需要使用关键字作为...
通过System.Reflection命名空间中的类,如Type、MethodInfo、PropertyInfo等,我们可以获取到类的元数据,包括类名、属性、方法、构造函数等。 2. **获取类型信息**: - `typeof()`:静态方法,用于获取已知类型的...
综上所述,C#插件框架源代码的学习可以帮助开发者深入理解如何利用.NET Framework构建灵活、可扩展的应用程序。通过研究`Chsoft.Framework.Core`这个压缩包中的代码,你可以了解到如何组织代码、实现插件的加载、...
在C#编程语言的学习过程中,初学者通常会通过编写一系列小程序来熟悉语法、掌握基本概念并逐步提升编程技能。"c#初学者必须要会的30个c#小程序"这个资源正好提供了这样的实践机会。这些小程序涵盖了C#的基础到进阶...