【转】二、什么是反光、反射可以做些什么新匍京视频在线,【转】二、什么是反射、反射可以做些什么

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

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

什么是反光,反射能干嘛?

反射是:指程序能够访问、检测和修改它自身情况或作为的一种力量

反射是一种力量,所以给的概念就是表明了它能干嘛。

咱俩一直用反射重要做:

  • 收获项目标连带音讯
  • 动态调用方法
  • 动态构造对象
  • 从程序集中拿到类型。

如何是反射,反射能干嘛?

反射是:指程序可以访问、检测和改动它自身境况或作为的一种能力

反射是一种力量,所以给的定义就是讲明了它能干嘛。

俺们平常用反射重要做:

  • 得到项目标连带消息
  • 动态调用方法
  • 动态构造对象
  • 从程序集中拿到类型。

取得项目标有关音讯

反射的核心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#基础知识巩固序列

相关文章