简单来说,反射提供这样几个能力:
1、查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata);
2、迟绑定(Late-Binding)方法和属性。
3、动态创建类型实例(并可以动态调用所创建的实例的方法、字段、属性)。
public abstract class Type : MemberInfo, _Type, IReflect
|
使用 System.Type 访问元数据
类型的名称是什么( Type.Name )?
类型是public吗( Type.IsPublic )?
类型的基类型是什么( Type.BaseType )?
类型支持任何接口吗( Type.GetInterfaces() )?
类型是哪个程序集中定义的( Type.Assembly )?
类型的属性( Type.GetProperties() )、方法( Type.GetMethods() )、字段( Type.GetFields() )是什么?
都有什么特性在修饰一个类型( Type.GetCustomAttributes() )?
获取Type对象的引用方法:
1. object.GetType()
2. typeof()
object 包含一个 GetType() 方法。所以所有类型都包含。
- DateTime dateTime = new DateTime();
-
- Type type = dateTime.GetType();
- Console.WriteLine("属性:");
- foreach (System.Reflection.PropertyInfo property in type.GetProperties())
- {
- Console.WriteLine(property.Name);
- }
|
调用 GetType() 的关键在于获得一个对象实例,但有些时候不能获取,例如,静态类就无法实例化,所以没法调用。
2.typeof()
- Type type = typeof (DateTime);
|
2.获取其他类型的相关信息(命名空间名、全名、是否是抽象、是否是类、、、等等)
命名空间名、全名、是否是抽象、是否是类、、、等等
- Type type = typeof (DateTime);
- Console.WriteLine("命名空间名称:" + type.Namespace);
- Console.WriteLine("直接基类型:" + type.BaseType);
- Console.WriteLine("全名:" + type.FullName);
- Console.WriteLine("是抽象类型:" + type.IsAbstract);
- Console.WriteLine("是类:" + type.IsClass);
|
3.获取类型成员信息(通过Tyep中的方法GetMembers)
- DateTime dateTime = new DateTime();
- Type type = typeof(DateTime);
- var mers = type.GetMembers();
- foreach (var mer in mers)
- {
- Console.WriteLine("【" + mer.MemberType.ToString() + "】:" + mer.Name);
- }
|
MemberTypes
MemberType 属性的返回类型为 MemberTypes ,这是一个枚举,它定义了用于表示不同成员的类型值。因此可以通过检查 MemberType 属性来确定成员的类型,例如,在 MemberType 属性的值为 MemberTypes.Method 时,该成员为方法。
MemberType 所能包含的成员类型有哪些呢?
if (mer.MemberType == MemberTypes.Method)
|
注意:
其中 MemberInfo 的属性 DeclaringType 返回的是这个属性定义的类型,
而 ReflectedType 返回的是获取这个属性的对象类型
先来个类:
- public class Dog { }
输出:
- Type type = typeof(Dog);
- var mers = type.GetMembers();
-
- foreach (var mer in mers)
- {
- if (mer.Name == "Equals")
- {
- Console.WriteLine("【" + mer.MemberType + "】:" + mer.Name);
- }
- }
|
4.动态调用方法
- public class TClass
- {
- public void fun(string str)
- {
- Console.WriteLine("我是fun方法,我被调用了。" + str);
- }
- public void fun2()
- {
- Console.WriteLine("我是fun2方法,我被调用了。");
- }
-
- public static void fun3()
- {
- Console.WriteLine("我是fun3静态方法,我被调用了");
- }
- }
|
调用方式一(使用InvokeMember调用方法)
调用带参实例方法fun
Type T1 = typeof(TClass); T1.InvokeMember( "fun", System.Reflection.BindingFlags.InvokeMethod, //是一个枚举,表示是调用一个方法 null, new TClass(), new string[] { "test" });
|
调用无参实例方法fun2
Type T2 = new TClass().GetType(); T2.InvokeMember("fun2", System.Reflection.BindingFlags. InvokeMethod, null, new TClass(), null);
|
调用静态方法
Type T3 = typeof(TClass); T3.InvokeMember("fun3", System.Reflection.BindingFlags.InvokeMethod, null, T1, null);
|
调用方式二(使用MethodInfo.Invoke调用方法)
- Type T1 = typeof(TClass);
- T1.GetMethod("fun", BindingFlags.Instance | BindingFlags.Public).Invoke(new TClass(), new string[] { "testfun1" });
- T1.GetMethod("fun2", BindingFlags.Instance | BindingFlags.Public).Invoke(new TClass(), null);
- T1.GetMethod("fun3", BindingFlags.Static | BindingFlags.Public).Invoke(T1, null);
|
使用其实和上面的方式一区别不大。
3.真正的全动态调用
- Console.WriteLine("请输入对象类名");
- string className = Console.ReadLine();
- Console.WriteLine("请输入要执行的方法名");
- string funName = Console.ReadLine();
- Type T1 = Type.GetType(className);
-
- ConstructorInfo ci = T1.GetConstructors()[0];
- var obj = ci.Invoke(null);
-
- T1.InvokeMember(funName, BindingFlags.InvokeMethod, null, obj, null);
|
当然,这个代码只能只是
fun2 ,因为上面的传参写死了。
5.动态构造对象
先定义一个对象
public class TClass { public string Name { get; set; } public TClass() { Console.WriteLine("构造函数被执行了。。"); } public TClass(string str) { Console.WriteLine("有参构造函数被执行了。。" + str); } }
|
动态构造对象
Assembly asm = Assembly.GetExecutingAssembly(); TClass obj = (TClass)asm.CreateInstance("动态调用.tclass", true); ObjectHandle handler = Activator.CreateInstance(null, " 动态调用.TClass"); obj = (TClass)handler.Unwrap(); Assembly asm2 = Assembly.GetExecutingAssembly(); obj = (TClass)asm2.CreateInstance("动态调用.tclass", true, BindingFlags.Default, null, new string[] { "test" }, null, null);
|
6.获取和修改属性
使用上面的类
var obj = new TClass(); obj.Name = "张三"; Type type = typeof (TClass); var name = type.InvokeMember("Name", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null, obj, null); Console.WriteLine("name:"+obj.Name); type.InvokeMember("Name", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { "新属性(李四)" }); Console.WriteLine(obj.Name);
|
7.从程序集中获得类型
取得当前代码所在程序集(使用GetExecutingAssembly)
Assembly ass = Assembly.GetExecutingAssembly(); Console.WriteLine("当前所在程序集名:" + ass.ManifestModule.Name); Console.WriteLine("当前所在程序集路径:" + ass.Location);
|
通过反射加载程序集并创建程序中的类型对象
从程序集中获得类型,这个应该是我们平时用得比较多。如我们所谓的依赖注入和控制反转就用到了通过反射从程序集中获取类型。
首先我们还是看看怎么从程序集中获得类型吧。我们可以使用 Assembly 类型提供的静态方法 LoadFrom() 或 Load() ,如:
Assembly asm1 = Assembly.LoadFrom("动态调用.exe"); Assembly asm2 = Assembly.Load("动态调用");
|
两者区别:
Assembly asm = Assembly.LoadFrom("动态调用.exe"); Assembly asm2 = Assembly.Load("动态调用"); TClass obj = (TClass)asm2.CreateInstance("动态调用.tclass", true); Console.WriteLine(obj.Name);
|
这样带来的功能是非常强大的。如 我们在没有引用程序集的情况下,也可以使用到程序外的程序集。我们还可以根据不同情况引用不同的程序集。我们甚至还可以通过配置文件来直接配置代码运行时应该加载哪个dll,运行哪个dll中的哪个实现方法。(下篇在讲依赖注入的时候会讲到,同学们继续关注哦~)
从上所知,反射不是某一个概率,而是一类操作的统称。或者说是某些能力的统称。 感觉不好回答反射到底是什么,只能说反射能干什么。它能动态创建对象、动态调用对象方法、动态读取和设置属性和字段、它能动态加载程序外的dll。总的感觉就是大多数都是跟“动态”扯上了关系。
农码一生 《二、什么是反射、反射可以做些什么》
相关阅读:
Windows共享上网的做法
如何花更少的时间学习更多的知识
因权限引起的svn提交失败的错误及其解决办法
ArcGIS二次开发入门(一)
GeoTiff如何存储颜色表的研究
html5文件夹上传源码
vue文件夹上传源码
前端文件夹上传源码
asp.net文件夹上传源码
使用webuploader实现大文件上传分片上传
原文地址:https://www.cnblogs.com/tangge/p/6100389.html