啼血必发365乐趣网投手机版

by admin on 2018年12月24日

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

自述:诗是作者书发自己的心情。

怎样是反射,反射能干嘛?

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

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

我们向来用反射重要做:

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

:

取得项目标连锁音讯

反射的核心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又能拿到些什么消息吗?

必发365乐趣网投手机版 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);
//.....等等

必发365乐趣网投手机版 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 是成员类型
}

必发365乐趣网投手机版 3

MemberType所能包含的分子类型有怎样吧?如:(可以友善可以F12进来看看)

必发365乐趣网投手机版 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中调用的,所以:

必发365乐趣网投手机版 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用法分别不大。

终日在枝头哀歌

动态调用方法

先是定义个类:

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" });

必发365乐趣网投手机版 6

调用无参实例方法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);

 必发365乐趣网投手机版 7

应用其实和地点的法子一区分不大。

后天的风向

真的的全动态调用

地点的二种形式,在编辑代码的时候总是要先确定了已知的目的名和章程名。那么我们在不知底对象和措施名的时候是否也得以调用呢?答案是毫无疑问的,实现如下:

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了) 

效率如下:(对象名和办法名都是手动输入的)

必发365乐趣网投手机版 8

吹拆了自我柔弱的翅膀

动态构造对象

大家先定义一个对象:

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:不区分大小写            

履行职能图:

必发365乐趣网投手机版 9

挣扎中不能脱身的

收获和改动属性

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);//获取值

必发365乐趣网投手机版 10

是自己的命宫

从程序集中得到类型

在一个糊弄的小日子

获取当前代码所在程序集(使用GetExecutingAssembly)

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

 必发365乐趣网投手机版 11

乘胜方向不定的季风

通过反射加载程序集并成立程序中的类型对象

从程序集中拿到类型,这么些应该是我们一直用得相比较多。如我辈所谓的依靠注入和操纵反转(这几个核心将在下篇博文举行解析)就用到了经过反射从程序集中获取项目。

先是大家依旧看看怎么从程序集中拿到类型吧。我们可以行使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#基础知识巩固体系

我迷失在一个梦中

从未人报告自己再次来到的道路

自身声声呼唤

迷失在另一个梦中。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图