【转】二、什么是反光、反射可以开来什么。我们取得已加载程序集中类型的Type对象的几种植办法。

【转】二、什么是反光、反射可以做些什么

啊是反光,反射能干嘛?

照是:指程序可以看、检测和修改它自身状态或行为的等同栽力量

照是平等种植力量,所以让的概念就是认证了它能够干嘛。

我们平素为此反射主要做:

  • 博项目的系信息
  • 动态调用方法
  • 动态构造对象
  • 自从程序集中取路。

咦是反射,反射能干嘛?

照是:指程序可以拜、检测及改其本身状态或行为的一致种植能力

映是同等栽能力,所以叫的定义就是认证了她能干嘛。

俺们平常于是反射主要做:

  • 取得项目的相干信息
  • 动态调用方法
  • 动态构造对象
  • 由程序集中取路。

获取项目的连锁消息

照的核心Type类,Type对象提供的习性与艺术可收获对象的一体信息,如:方法、字段、属性、事件…等等。

咱沾已加载程序集中类型的Type对象的几乎种植办法:(以StringBuilder 类型为例)

  1. 直动用typeof操作符 Type T1 = typeof(StringBuilder); 
  2. 经过项目实例 Type T2 = new
    StringBuilder().GetType(); 
  3. 经Type类的静态方法 Type T3 = Type.GetType(“System.IO.Stream”); 

任凭采取那种,我们最后收获的结果都是一律的。

那我们透过Type又能获取些什么信息也?

取得项目的相关消息

照的核心Type类,Type对象提供的属性与方法好落对象的全套信息,如:方法、字段、属性、事件…等等。

咱赢得已加载程序集中类型的Type对象的几乎栽办法:(以StringBuilder 类型为例)

  1. 直以typeof操作符 Type T1 = typeof(StringBuilder); 
  2. 经过项目实例 Type T2 = new StringBuilder().GetType(); 
  3. 经Type类的静态方法 Type T3 = Type.GetType(“System.IO.Stream”); 

甭管采取那种,我们最后赢得的结果都是千篇一律的。

那么我们透过Type又能博得些什么消息吗?

抱类我信息(命名空间名、全名、是否是架空、是否是类、、、等等)

var T1 = typeof(StringBuilder);                      
Console.WriteLine("命名空间名称:" + T1.Namespace);
Console.WriteLine("直接基类型:" + T1.BaseType);
Console.WriteLine("全名:" + T1.FullName);
Console.WriteLine("是抽象类型:" + T1.IsAbstract);
Console.WriteLine("是类:" + T1.IsClass);
//.....等等

图片 1

取得项目我信息(命名空间名、全名、是否是抽象、是否是类、、、等等)

var T1 = typeof(StringBuilder);                      
Console.WriteLine("命名空间名称:" + T1.Namespace);
Console.WriteLine("直接基类型:" + T1.BaseType);
Console.WriteLine("全名:" + T1.FullName);
Console.WriteLine("是抽象类型:" + T1.IsAbstract);
Console.WriteLine("是类:" + T1.IsClass);
//.....等等

图片 2

赢得类成员信息(通过Tyep中的方GetMembers)

Type T1 = typeof(TClass);
var Mets = T1.GetMembers();//获取Type对象的所有公有成员           
foreach (var m in Mets)
{
    Console.WriteLine("【" + m.MemberType.ToString()+ "】:" + m.Name);
    // m.MemberType 是成员类型
}

图片 3

MemberType所能够包含的成员类型有安也?如:(可以协调可以F12上看看)

图片 4

留神:其中MemberInfo的性能DeclaringType返回的是这特性定义之品类,而ReflectedType返回的凡得到之特性之靶子类型。

如:

Type T2 = typeof(TClass);
var Mets = T2.GetMembers();//获取所有公共成员(返回值是MemberInfo类型集合)
foreach (var m in Mets)
{
    if (m.Name=="Equals")
    {
        Console.WriteLine("【" + m.MemberType.ToString() + "】:" + m.Name);
        // m.MemberType 是成员类型

        // m.DeclaringType;//获取申明该成员的类
        // m.ReflectedType;//获取用于获取 MemberInfo 的此实例的类对象。 

    } 
}

T2中的Equals,我们明白者办法是于Objec中定义的,在TClass中调用的,所以:

图片 5

咱俩发现得Type对象的分子大多还是为 isxxx、Getxxx、Getxxxs格式的。

isxxx格式的多都是判定是否是某某项目。

Getxxx和Getxxxs都是放开回某类型以及某型集合。其中要的品种有:

//FieldInfo封装了关于字段的所有信息   (通过Tyep对象的GetFields或GetField方法)

//PropertyInfo类型,封装了类型的属性信息;(通过Type对象的GetProperties或GetProperty方法)

//ConstructorInfo类型,封装了类型的构造函数信息; (..........)

//MethodInfo类型,封装了类型的方法信息;  (........)

//MemberInfo类型,封装了类型的所有公共成员;(**就是我们上面说的GetMembers方法**)

//EventInfo类型,封装了类型的事件信息;(.......)

//ParameterInfo类型,封装了方法和构造函数的参数信息;(........)

她还当 System.Reflection 命名空间下,其每个isxxx、Getxxx、Getxxxs的细节实例用法虽不一一演示了。和地方的GetMembers用法分别不怪。

收获类成员信息(通过Tyep中的方法GetMembers)

Type T1 = typeof(TClass);
var Mets = T1.GetMembers();//获取Type对象的所有公有成员           
foreach (var m in Mets)
{
    Console.WriteLine("【" + m.MemberType.ToString()+ "】:" + m.Name);
    // m.MemberType 是成员类型
}

图片 6

MemberType所能够包含的积极分子类型有怎样呢?如:(可以团结好F12进来看看)

图片 7

专注:其中MemberInfo的习性DeclaringType返回的凡其一特性定义的型,而ReflectedType返回的是取得这特性的靶子类型。

如:

Type T2 = typeof(TClass);
var Mets = T2.GetMembers();//获取所有公共成员(返回值是MemberInfo类型集合)
foreach (var m in Mets)
{
    if (m.Name=="Equals")
    {
        Console.WriteLine("【" + m.MemberType.ToString() + "】:" + m.Name);
        // m.MemberType 是成员类型

        // m.DeclaringType;//获取申明该成员的类
        // m.ReflectedType;//获取用于获取 MemberInfo 的此实例的类对象。 

    } 
}

T2中之Equals,我们知道这主意是在Objec中定义的,在TClass中调用的,所以:

图片 8

咱发现沾Type对象的积极分子多都是坐 isxxx、Getxxx、Getxxxs格式的。

isxxx格式的大半都是判是否是某某项目。

Getxxx和Getxxxs都是加大回某类型以及某型集合。其中要的种类有:

//FieldInfo封装了关于字段的所有信息   (通过Tyep对象的GetFields或GetField方法)

//PropertyInfo类型,封装了类型的属性信息;(通过Type对象的GetProperties或GetProperty方法)

//ConstructorInfo类型,封装了类型的构造函数信息; (..........)

//MethodInfo类型,封装了类型的方法信息;  (........)

//MemberInfo类型,封装了类型的所有公共成员;(**就是我们上面说的GetMembers方法**)

//EventInfo类型,封装了类型的事件信息;(.......)

//ParameterInfo类型,封装了方法和构造函数的参数信息;(........)

它还在 System.Reflection 命名空间下,其每个isxxx、Getxxx、Getxxxs的底细实例用法即不一一演示了。和点的GetMembers用法分别不雅。

动态调用方法

率先定义个类:

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静态方法,我被调用了");
    }
}

动态调用方法

第一定义个类:

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", BindingFlags.InvokeMethod, null, new TClass(), new string[] { "test" });

图片 9

调用无参实例方法fun2

Type T1 = typeof(TClass);
T1.InvokeMember("fun2", BindingFlags.InvokeMethod, null, new TClass(), null);

调用静态方法

Type T1 = typeof(TClass);
T1.InvokeMember("fun3", BindingFlags.InvokeMethod, null, T1, null);

咱俩发现了一个题目当我们调用实例方法的时节用传实例对象过去。(有人会说,都实例对象了,我还要你动态掉调用个屁啊。有种植情况,在咱们实例了目标后,仍无确定该调用那个方式时方可只有采取。然后有人发生说了,那如实例对象自我也未确定为?那我们下会分析并实例对象啊给动态了。那就完下看吧。)

俺们来说下立刻几乎单参数的意思吧。

率先只:要给动态调用的措施名。

亚单:是一个枚举,表示是调用一个术

其三独:是Binder,传的凡null,使用默认值。

季单:传如实例对象(调用实例方法时)或者Type对象(调用静态方法时)。

第五个:要招被吃调用发的参数数组。

调用方式同样(使用InvokeMember调用智)

调用带参实例方法fun

Type T1 = typeof(TClass);
T1.InvokeMember("fun", BindingFlags.InvokeMethod, null, new TClass(), new string[] { "test" });

图片 10

调用无参实例方法fun2

Type T1 = typeof(TClass);
T1.InvokeMember("fun2", BindingFlags.InvokeMethod, null, new TClass(), null);

调用静态方法

Type T1 = typeof(TClass);
T1.InvokeMember("fun3", BindingFlags.InvokeMethod, null, T1, null);

咱俩发现了一个题材当我们调用实例方法的时要传实例对象过去。(有人会说,都实例对象了,我还要你动态掉调用个屁啊。有种植情况,在咱们实例了对象后,仍无确定该调用那个方式时方可只有采取。然后有人发生说了,那如实例对象自我啊未确定为?那我们下会分析并实例对象啊给动态了。那就完下看吧。)

咱俩来说下这几乎单参数的意思吧。

率先只:要让动态调用的办法名。

亚个:是一个枚举,表示是调用一个术

其三独:是Binder,传的凡null,使用默认值。

季单:传如实例对象(调用实例方法时)或者Type对象(调用静态方法时)。

第五个:要招给吃调用发的参数数组。

调用方式二(使用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);

 图片 11

使其实和方面的方法一样区分不十分。

调用方式二(使用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);

 图片 12

使用其实与点的主意一样分不甚。

审的全动态调用

点的有数种植办法,在编写代码的时总是要先期确定了已经领略之对象名以及办法名。那么我们在无知晓对象以及章程名之时段是不是为可以调用呢?答案是得之,实现如下:

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,因为上面的传参写死了。(你也可以友善有些修改下,就足以推行fun、fun2、fun3了) 

功能如下:(对象名以及方名都是手动输入的)

图片 13

真正的全动态调用

面的一定量种方法,在编辑代码的当儿总是要先确定了已经了解的目标名及办法名。那么我们以匪懂得对象及方名的下是不是为得以调用呢?答案是必定之,实现如下:

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,因为地方的传参写好了。(你吗可以自己有点修改下,就可以推行fun、fun2、fun3了) 

意义如下:(对象名与法名都是手动输入的)

图片 14

动态构造对象

我们先定义一个对象:

public class TClass
{
    public TClass()
    {
        Console.WriteLine("构造函数被执行了。。");
    }
    public TClass(string str)
    {
        Console.WriteLine("有参构造函数被执行了。。" + str);
    }        
}

动态构造对象

//动态构造对象,方式一
Assembly asm = Assembly.GetExecutingAssembly();
TClass obj = (TClass)asm.CreateInstance("net.tclass", true);//true:不区分大小写

//动态构造对象,方式二
ObjectHandle handler = Activator.CreateInstance(null, " net.TClass");//null:当前程序集
obj = (TClass)handler.Unwrap();

//动态构造对象,方式三(构造有参构造函数)
Assembly asm2 = Assembly.GetExecutingAssembly();
obj = (TClass)asm2.CreateInstance("net.tclass", true, BindingFlags.Default, null, new string[] { "test" }, null, null);//true:不区分大小写            

推行效力图:

图片 15

动态构造对象

俺们先定义一个目标:

public class TClass
{
    public TClass()
    {
        Console.WriteLine("构造函数被执行了。。");
    }
    public TClass(string str)
    {
        Console.WriteLine("有参构造函数被执行了。。" + str);
    }        
}

动态构造对象

//动态构造对象,方式一
Assembly asm = Assembly.GetExecutingAssembly();
TClass obj = (TClass)asm.CreateInstance("net.tclass", true);//true:不区分大小写

//动态构造对象,方式二
ObjectHandle handler = Activator.CreateInstance(null, " net.TClass");//null:当前程序集
obj = (TClass)handler.Unwrap();

//动态构造对象,方式三(构造有参构造函数)
Assembly asm2 = Assembly.GetExecutingAssembly();
obj = (TClass)asm2.CreateInstance("net.tclass", true, BindingFlags.Default, null, new string[] { "test" }, null, null);//true:不区分大小写            

实施职能图:

图片 16

收获与修改属性

var obj = new TClass();
obj.name = "张三";
Type type = typeof(TClass);
//获取属性
var Name = type.InvokeMember("name", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null,
                     obj, new object[] { }) as string;
Console.WriteLine(obj.name);
//设置属性
type.InvokeMember("name", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, null,
                      obj, new object[] { "新属性(李四)" });
Console.WriteLine(obj.name);

//=====================

PropertyInfo[] pros = type.GetProperties(---);//

PropertyInfo pro = null;

var value = pro.GetValue(type);//获取值

图片 17

得和改动属性

var obj = new TClass();
obj.name = "张三";
Type type = typeof(TClass);
//获取属性
var Name = type.InvokeMember("name", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null,
                     obj, new object[] { }) as string;
Console.WriteLine(obj.name);
//设置属性
type.InvokeMember("name", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, null,
                      obj, new object[] { "新属性(李四)" });
Console.WriteLine(obj.name);

//=====================

PropertyInfo[] pros = type.GetProperties(---);//

PropertyInfo pro = null;

var value = pro.GetValue(type);//获取值

图片 18

起程序集中取路

于程序集中取路

博时代码所在程序集(使用GetExecutingAssembly)

Assembly ass = Assembly.GetExecutingAssembly();
Console.WriteLine("当前所在程序集名:"+ass.ManifestModule.Name);
Console.WriteLine("当前所在程序集路径:"+ass.Location);

 图片 19

落时代码所在程序集(使用GetExecutingAssembly)

Assembly ass = Assembly.GetExecutingAssembly();
Console.WriteLine("当前所在程序集名:"+ass.ManifestModule.Name);
Console.WriteLine("当前所在程序集路径:"+ass.Location);

 图片 20

经反射加载程序集并创造程序中的种类对象

起程序集中取路,这个理应是我们平常就此得比多。如我辈所谓的仗注入及操纵反转(这个主题将在下篇博文进行辨析)就用到了经过反射从程序集中取类。

首先我们或看看怎么由程序集中取路吧。我们得以利用Assembly类型提供的静态方法LoadFrom()或Load(),如:

Assembly asm = Assembly.LoadFrom("Demo.dll");
Assembly asm = Assembly.Load("Demo");

区别:

Assembly asm = Assembly.LoadFrom("net.exe");//需要加后缀,可以指定路径,如下面的
Assembly asm1 = Assembly.LoadFrom(@"C:\01文件\05Svn\BlogsCode\Blogs\Blogs.Web\bin\Blogs.BLL.dll");

Assembly asm2 = Assembly.Load("Blogs.BLL");//无需加后缀,不可以指定路径
//Assembly asm3 = Assembly.Load(@"C:\01文件\05Svn\BlogsCode\Blogs\Blogs.Web\bin\Blogs.BLL");//这里会报错
//使用Load可以加载当前程序bin目录行下的程序集或者系统程序集

//这里TClass可以是一个接口,那么可以在外面的dll任意实现了。  
TClass obj = (TClass)asm2.CreateInstance("net.tclass", true);//true:不区分大小写
obj.fun();//***调用动态加载的dll中的方法***

然带来的力量是蛮强大的。如
我们于并未引用程序集的情景下,也堪采取及程序外的次第集。我们还得依据不同情形引用不同的顺序集。我们还还可由此部署文件来一直配置代码运行时当加载哪个dll,运行哪个dll中之哪位实现方式。(下篇在说依赖注入的早晚会说话到,同学等继承关心哦~)

从今上所了解,反射不是某个一个概念,而是同好像操作的统称。或者说是某些能力的统称。
感觉不好回答反射到底是啊,只能说反射能干啊。它能动态创建对象、动态调用对象方法、动态读取和装属性与字段、它亦可动态加载程序外的dll。总的觉得就是是大部分还是与“动态”扯上了涉嫌。

 


 

加:跨程序集反射

若果我们反射A.dll,而A.dll中援引了B.dll,那么以assembly.GetTypes();
//运行到是地方会弹有如下错误描述

 

“未处理
System.Reflection.ReflectionTypeLoadException Message=”无法加载一个还是多个请求的型。有关还多信息,请检索LoaderExceptions属性。”

 

这种情形可以

 

Assembly assembly =  Assembly.LoadFrom(“A.dll”) ;
Type type = assembly.GetType(“xxx.myclassname”) ; //传入对应之待反射的品类
而无克GetTypes。且,应用程序需要以A.dll锁依赖的B.dll。

 

正文为联合到《C#基础知识巩固系列》

经反射加载程序集并创造程序中的色对象

自从程序集中取路,这个当是咱们平素因故得较多。如我们所谓的依靠注入和控制反转(这个主题将于下篇博文进行剖析)就就此到了通过反射从程序集中取项目。

率先我们要看怎么从程序集中取路吧。我们得以用Assembly类型提供的静态方法LoadFrom()或Load(),如:

Assembly asm = Assembly.LoadFrom("Demo.dll");
Assembly asm = Assembly.Load("Demo");

区别:

Assembly asm = Assembly.LoadFrom("net.exe");//需要加后缀,可以指定路径,如下面的
Assembly asm1 = Assembly.LoadFrom(@"C:\01文件\05Svn\BlogsCode\Blogs\Blogs.Web\bin\Blogs.BLL.dll");

Assembly asm2 = Assembly.Load("Blogs.BLL");//无需加后缀,不可以指定路径
//Assembly asm3 = Assembly.Load(@"C:\01文件\05Svn\BlogsCode\Blogs\Blogs.Web\bin\Blogs.BLL");//这里会报错
//使用Load可以加载当前程序bin目录行下的程序集或者系统程序集

//这里TClass可以是一个接口,那么可以在外面的dll任意实现了。  
TClass obj = (TClass)asm2.CreateInstance("net.tclass", true);//true:不区分大小写
obj.fun();//***调用动态加载的dll中的方法***

诸如此类带的功效是可怜强劲的。如
我们当没引用程序集的状况下,也得采用到程序外的程序集。我们尚足以因不同情形引用不同的次集。我们还还好透过配备文件来直接配置代码运行时该加载哪个dll,运行哪个dll中之谁实现方式。(下篇在言语依赖注入的上会摆到,同学等继续关心哦~)

自达所掌握,反射不是某一个概念,而是同样看似操作的统称。或者说是某些能力的统称。
感觉不好回答反射到底是呀,只能说反射能干啊。它能动态创建对象、动态调用对象方法、动态读取和装属性与字段、它能够动态加载程序外的dll。总的感觉就是大部分且是与“动态”扯上了事关。

 


 

加:跨程序集反射

倘我们反射A.dll,而A.dll中引用了B.dll,那么当assembly.GetTypes();
//运行及此地方会面弹有如下错误描述

 

“未处理
System.Reflection.ReflectionTypeLoadException Message=”无法加载一个或多个请求的品种。有关还多信息,请检索LoaderExceptions属性。”

 

这种情形好

 

Assembly assembly =  Assembly.LoadFrom(“A.dll”) ;
Type type = assembly.GetType(“xxx.myclassname”) ; //传入对应的急需反射的类
而无可知GetTypes。且,应用程序需要以A.dll锁依赖的B.dll。

 

正文为协同到《C#基础知识巩固系列》

相关文章