必发365bifa0000【转】二、什么是反光、反射可以做些什么

by admin on 2018年12月26日

   

【转】二、什么是反射、反射能够做些什么

必发365bifa0000 1

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

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

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

咱俩平常用反射首要做:

  • 赢得项目的连锁音讯
  • 动态调用方法
  • 动态构造对象
  • 从程序集中得到类型。

       
我的简书写作终于迎来第一百篇。依照当初每一天一篇的考虑,其实在上个月的十五号自身就应有完成了,然则足足晚了二十多天。也就是说,这里面有二十多天自己没有形成日更,我偷闲了。

获取项目标有关音讯

反射的主旨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);
//.....等等

必发365bifa0000 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 是成员类型
}

必发365bifa0000 3

MemberType所能包含的分子类型有如何吧?如:(可以团结可以F12跻身看看)

必发365bifa0000 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中调用的,所以:

必发365bifa0000 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" });

必发365bifa0000 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);

 必发365bifa0000 7

动用其实和下面的法门一分别不大。

必发365bifa0000 8

实在的全动态调用

地点的二种形式,在编辑代码的时候总是要先确定了已知的对象名和方法名。那么大家在不了解对象和章程名的时候是否也能够调用呢?答案是自然的,实现如下:

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

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

必发365bifa0000 9

动态构造对象

我们先定义一个目的:

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

实践效用图:

必发365bifa0000 10

获取和改动属性

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

必发365bifa0000 11

从程序集中得到类型

赢得当前代码所在程序集(使用GetExecutingAssembly)

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

 必发365bifa0000 12

透过反射加载程序集并创设程序中的类型对象

从程序集中拿到类型,那一个相应是我们平日用得相比多。如我辈所谓的倚重性注入和控制反转(这一个主旨将在下篇博文举行剖析)就用到了通过反射从程序集中获取项目。

先是我们依旧看看怎么从程序集中拿到类型吧。我们可以应用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地图