【转】二、什么是反光、反射可以做些什么,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#基础知识巩固体系

相关文章