架构师的入门基础
分类:计算机编程

前言

反射

自家精晓:

编制程序其实正是写代码,而写代码目标正是促成业务,所以,语法和框架也是为着完毕职业而存在的。由此,不管多么庞大上的靶子,实质上都以职业。

简介

  反射是 .NET中的首要机制,通过反射,可以在运维时获得程序或程序聚焦类型(富含class、struct、delegate、interface 和 enum 等)的积极分子和成员的新闻。

  通过反射,就能够对每生机勃勃种档期的顺序成竹于胸,况且也得以通过反射创设、调用和做客对象,固然在编写翻译时不明确该目的的品种。

  程序集带有模块,模块包括类型,而项目包括成员。反射提供包装程序集、模块和品种的指标。能够使用反射动态地成立项目的实例,将品种绑定到存活对象,或从现存对象中获得项目。

装配件:Assembly(程序集)

之所以,我觉着毫无把写代码上升到科学的中度。上涨到方法就能够了,因为艺术本身也绝非惊人。。。。

优缺点

  优点:

  1. 做实了程序的布帆无恙和扩充性;
  2. 减少耦合性;
  3. 它同意程序创设和决定其余类的目的,没有必要提前硬编码指标类。

  缺点:

  1. 属性:使用反射基本上是风流倜傥种解释操作,从理论上讲使用反射远慢于直接代码;
  2. 可读性收缩。

晚绑定:中期绑定

软件设计存在过度设计,语法和框架的掌握,也存在过度通晓。举例,反编译下,看看反射是怎么贯彻的。。。

反射的门类成员音信

  • Assembly:定义和加载程序集。

  • Module:模块音信(如含有模块的程序集和模块中的类)。

  • ConstructorInfo:构造函数消息(如名称、参数、采访修饰符等)。
  • MethodInfo:方法成员信息(如名称、重返类型、参数和做客修饰符等)。

  • FieldInfo:字段成员消息(如名称、访谈修饰符)。

  • EventInfo:事件成员消息(如名称、事件管理程序的数据类型、自定义天性、表明类型甚至事件的反光的档案的次序)。

  • PropertyInfo:属性成员新闻(如名称、数据类型、申明类型,反射的类型和属性的只读或可写状态),并获取或安装属性值。

  • ParameterInfo:参数成员消息(如参数名、数据类型以至参数在措施签字中之处等)。

  • CustomAttributeData:自定义特性音信。

  System.Reflection.Emit命名空间的类提供意气风发种专用形式的反射,使您可见在运营时生成类型。

MSDN:反射(C# 编制程序指南).aspx)

有意思味是好事,但即使知道了反光的面目,领会了反光是怎么样规划的,你技能也没怎么质的改变。因为,本领水平最后如故要贯彻到利用上。

反射的简约用法

  命名空间:System.Reflection、System.Type、System.Reflection.Assembly

  家常便饭的获得 Type 对象的用法:

            Type type1 = typeof(string);            string msg = "";            Type type2 = msg.GetType();

-----------------原著如下--------

在诸如,过度的言情代码质量,也未见得是大器晚成件善事,因为,[大多数]场馆下,硬件比技术员低价多了。。。(注意这里指的是代码不是算法和数据库品质)

二个大范围的亲自过问用法

  大家一齐始上学三层架构的时候,都应当会自个儿接着导师出手创设二个SqlHelper 的吗,这里本身截取四个经过反射读取数据库数据并填充到三个目的的属性上,通过轮回遍历,最终生成三个list 列表的代码。

        /// <summary>        /// 执行 Reader 并读取数据转换成集合        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="sql"></param>        /// <param name="commandType"></param>        /// <param name="parameters"></param>        /// <returns></returns>        public static IList<T> ExecuteReaderToList<T>(string sql, CommandType commandType = CommandType.Text,            params SqlParameter[] parameters) where T : new()        {            var type = typeof;            var props = type.GetProperties();            var list = new List<T>();            using (var reader = ExecuteDataReader(sql, commandType, parameters))            {                while (reader.Read                {                    var entity = new T();                    foreach (var propertyInfo in props)                    {                        var schemaTable = reader.GetSchemaTable();                        if (schemaTable == null)                            return new List<T>();                        schemaTable.DefaultView.RowFilter = $"ColumnName='{propertyInfo.Name}'";                        if (schemaTable.DefaultView.Count <= 0) continue;                        if (!propertyInfo.CanWrite)                            continue;                        var val = reader[propertyInfo.Name];                        if (val != DBNull.Value)                            propertyInfo.SetValue(entity, val);                    }                    list.Add;                }            }            return list;        }

  轻松深入分析应用反射的代码:

    type.GetProperties():获取属性集合;

    propertyInfo.CanWrite:可写属性;

    propertyInfo.SetValue(entity, val):属性赋值,接受相应的目的开展赋值。


反骨仔

微软官方文档

1、 什么是反光
2、 命名空间与装配件的关联
3、 运转期获得类型新闻有何样用
4、 如何运用反射获取项目
5、 怎样依据项目来动态成立对象
6、 怎么样赢得形式以至动态调用方法
7、 动态创设委托

于是,所有事,过度了,总不是好事。

1、什么是反光
        Reflection,汉语翻译为反射。
        那是.Net中得到运行时类型新闻的措施,.Net的应用程序由多少个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编制程序的方式,让程序猿能够在前后相继运转期获得那多少个组成都部队分的连带音信,举个例子:


        Assembly类能够得到正在运维的装配件音信,也能够动态的加载装配件,以致在装配件中搜寻类型音讯,并创建该项目标实例。
Type类能够获得对象的类型信息,此新闻包蕴对象的保有因素:方法、构造器、属性等等,通过Type类能够获得这么些成分的音信,何况调用之。
MethodInfo富含方法的音信,通过这么些类能够拿走方法的名目、参数、再次来到值等,而且能够调用之。
那般,还恐怕有菲尔德Info、伊芙ntInfo等等,那几个类都满含在System.Reflection命名空间下。

本篇小说主要介绍C#反射【用法】。

2、命名空间与装配件的关系
        超级多个人对那个概念大概依旧特别不清楚,对于合格的.Net技术员,有要求对这一点打开清淤。
        命名空间相像与Java的包,但又不完全等同,因为Java的包必需根据目录结构来放置,命名空间则无需。

反射是架设师必会的功底,因为其余叁个被规划出来的框架,都要接纳反射。

        装配件是.Net应用程序实践的小小单位,编译出来的.dll、.exe都以装配件。

反射也是最隐讳的语法,因为反射写出来后,平日它会被一直封装,然后调用者就只担任运用,不再关心她的现实落实。

        装配件和命名空间的涉嫌不是逐后生可畏对应,也不相互包涵,五个装配件里面能够有八个命名空间,几个命名空间也能够在多少个装配件中存在,那样说大概有一些模糊,举个例证:
装配件A:

那与它的特性有关,因为反射正是为着减削代码冗余而留存的,所以,看不见很正规。

  1. namespace  N1
  2. {
  3.       public  class  AC1  {…}
  4.       public  class  AC2  {…}
  5. }
  6. namespace  N2
  7. {
  8.       public  class  AC3  {…}
  9.       public  class  AC4{…}
  10. }

反射的定义

复制代码

法定概念:反射提供了包装程序集、模块和档期的顺序的靶子(Type 类型)。能够使用反射动态创设类型的实例,将项目绑定到现存对象,或从现成对象得到项目并调用其形式或访谈其字段和性质。若是代码中选用了品质,能够运用反射对它们进行访谈。

装配件B:

看不懂?不要紧,大家把它翻译中年人类可了解的言语。

  1. namespace  N1
  2. {
  3.       public  class  BC1  {…}
  4.       public  class  BC2  {…}
  5. }
  6. namespace  N2
  7. {
  8.       public  class  BC3  {…}
  9.       public  class  BC4{…}
  10. }

C#编制程序语言中,最常使用的是类和类中的函数和天性。正向调用的方法是,成立类,然后用类创制一个目的。接下来就足以用这一个目的调用类中的方法和品质了。

复制代码

而反射,正是相对于这种正向调用的存在。即,它是反向调用。

那七个装配件中都有N1和N2三个命名空间,而且各申明了八个类,这样是全然能够的,然后我们在一个应用程序中援用装配件A,那么在这里个应用程序中,大家能收看N1上边包车型客车类为AC1和AC2,N2下边包车型客车类为AC3和AC4。
        接着我们去掉对A的援用,加上对B的援引,那么我们在此个应用程序下能看见的N1下边包车型地铁类成为了BC1和BC2,N2上面也一直以来。
        要是大家同不平时间引述那多少个装配件,那么N1上面大家就能看出三个类:AC1、AC2、BC1和BC2。

反射能够因而类名的字符串来创立类,能够因此函数名的字符串和属性名的字符串,来调用类下的函数和性质。

        到此处,我们得以领略一个定义了,命名空间只是说美赞臣个项目是那多少个族的,比如有人是傣族、有人是阿昌族;而装配件表美素佳儿(Friso)个品种住在何地,举例有人住在首都、有人住在东京;那么北京有彝族人,也是有柯尔克孜族人,香水之都有独龙族人,也是有鄂伦春族人,那是不恶感的。

有同学会问了, 既然正向能够调用,那么反向调用干什么呢?

        上边大家说了,装配件是多个门类居住的地点,那么在二个顺序中要选拔二个类,就必得告诉编写翻译器那一个类住在哪个地方,编写翻译器技巧找到它,也正是说必需引用该装配件。
        那么只要在编写程序的时候,可能不显明那么些类在什么地方,仅仅只是知道它的名号,就不可能接收了啊?答案是足以,那便是反射了,就是在程序运转的时候提供该项指标地方,而去找到它。
有野趣的话,接着往下看呢。

会有这种题材的同校,先别发急,继续往下看,反射既然存在,就决然有存在的道理。

3、运营期获得类型音讯有哪些用
        有人大概难点,既然在支付时就可见写好代码,干嘛还停放运维期去做,不光繁琐,何况成效也受影响。
那就是个例外的难点了,就跟早绑定和晚绑定相符,应用到不相同的场子。有的人反驳晚绑定,理由是消耗功效,但是众四人在共享虚函数带来的补益的时侯还并未有发觉到他早已用上了晚绑定。那些标题说开去,不是片言只字能讲了解的,所以就点到甘休了。
        笔者的视角是,晚绑定能够推动众多设计上的有利,合适的行使能够大大升高程序的复用性和灵活性,不过任何事物都有两面性,使用的时侯,供给每每衡量。

反射的底蕴运用

紧接着说,运转期获得类型新闻到底有何用啊?
要么举个例证来表明,比较多软件开采者喜欢在融洽的软件中留下一些接口,其余人能够编写制定一些插件来扩展软件的效率,比方本身有二个媒体播放器,作者愿意以后能够很有利的扩充识别的格式,那么本身声圣元(Synutra)个接口:

1,类反射

  1. public  interface  IMediaFormat
  2. {
  3. string  Extension  {get;}
  4. Decoder  GetDecoder();
  5. }

先看下边代码;代码为经过类名称的字符,反射出类的对象。

复制代码

public class ReflectionSyntax
{ 
    public static void Excute()
    {
        Type type = GetType("Syntax.Kiba");
        Kiba kiba = (Kiba)Activator.CreateInstance(type);
        Type type2 = GetType2("Syntax.Kiba");
        Kiba kiba2 = (Kiba)Activator.CreateInstance(type2);
    }
    public static Type GetType(string fullName)
    {
        Assembly assembly = Assembly.Load("Syntax");
        Type type = assembly.GetType(fullName, true, false);
        return type;
    }

    public static Type GetType2(string fullName)
    {
        Type t = Type.GetType(fullName);
        return t;
    } 
} 
public class Kiba
{ 
    public void PrintName()
    {
        Console.WriteLine("Kiba518");
    } 
} 

那个接口中包涵七个Extension属性,那些本性再次回到扶助的扩张名,另八个主意再次来到七个解码器的靶子(这里小编只要了八个Decoder的类,那些类提供把文件流解码的效力,扩充插件能够派生之),通过解码器对象自己就足以解释文件流。
那正是说小编鲜明具备的解码插件都必需派生一个解码器,况兼完成那些接口,在GetDecoder方法中回到解码器对象,并且将其类别的名号配置到本人的布置文件之中。
这样的话,笔者就无需在开垦播放器的时侯知道未来扩展的格式的品种,只需求从布置文件中赢得现在抱有解码器的花色名称,而动态的创导媒体魄式的靶子,将其转移为IMediaFormat接口来使用。

在代码中我们看看,反射时传递了字符串"Syntax.Kiba",然后通过剖判字符串,获取到了该字符串对应的类的花色,最终再依靠Activator来支援成立类的实例。

那便是叁个反光的天下无双应用。

个中字符串"Syntax.Kiba"是一个通通节制名。什么是一心限制名?完全限制名正是命名空间 类名。在反射的时候,须要大家传递完全限制名来明确到底要去哪个命名空间,找哪些类。

4、如何使用反射获取项目
        首先大家来看什么获得类型新闻。
        得到类型音讯有三种办法,少年老成种是取得实例对象
        这一个时侯小编可是是获得那一个实例对象,获得的秘诀可能是二个object的援用,只怕是三个接口的引用,不过自身并不知道它的方便品种,笔者索要驾驭,那么就可以通过调用System.Object上宣称的不二法门GetType来获取实例对象的品种对象,比方在有个别方法内,小编索要看清传递步入的参数是不是贯彻了有个别接口,即便完毕了,则调用该接口的三个措施:

在代码中大家还足以观看,获取项目标艺术有三种,大器晚成种是较复杂的,生机勃勃种是简轻松单的。

  1. public  void  Process(  object  processObj  )
  2. {
  3. Type  t  =  processsObj.GetType();
  4. if(  t.GetInterface(“ITest”)  !=null  )
  5.                     …
  6. }

GetType2方法是总结的获取项目,通过Type直接就拆解深入分析了字符串。而GetType则先举办了加载Assembly(组件),然后再由组件获取项目。

复制代码

互相有怎么着分别呢?

此外豆蔻年华种得到项目标办法是由此Type.GetType以至Assembly.GetType方法,如:
              Type  t  =  Type.GetType(“System.String”);
        须求注意的是,后面大家讲到了命名空间和装配件的关联,要物色一个类,必需内定它所在的装配件,或许在已经赢得的Assembly实例下边调用GetType。
        本装配件中项目可以只写类型名称,另二个不及是mscorlib.dll,那个装配件中评释的连串也足以轻便装配件名称(.Net装配件编写翻译的时候,暗中认可都援引了mscorlib.dll,除非在编写翻译的时候分明钦赐不援引它),举例:
          System.String是在mscorlib.dll中宣示的,下面的Type  t  =  Type.GetType(“System.String”)是不错的
          System.Data.DataTable是在System.Data.dll中宣称的,那么:
Type.GetType(“System.Data.DataTable”)就不能不获得空引用。
          必须:
Type  t  =  Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0,  Culture=neutral,  PublicKeyToken=b77a5c561934e089");
          那样才得以,我们可以看上边那些帖子:
                http://expert.csdn.net/Expert/to ... 2.xml?temp=.1919977
          qqchen的答问很精美

有别于是,用Type直接解析,只好深入解析当前定名空间下的类。要是此类存在于引用的DLL中,就分析不了。

5、怎样依照项目来动态创设对象
        System.Activator提供了点子来根据项目动态创设对象,比如创制四个DataTable:

而GetType方法中的[Assembly.Load钦赐了前后相继集名],所以,在反射时,就能去钦点的命名空间里找对应的类。那样就能够找到非本前后相继集下的类了。

  1. Type  t  =  Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0,  Culture=neutral,  PublicKeyToken=b77a5c561934e089");
    1. DataTable  table  =  (DataTable)Activator.CreateInstance(t);

[Assembly.Load钦定了前后相继集名]那句话不佳驾驭?

复制代码

无妨,换个表达,Assembly.Load钦点了命名空间的称谓,所以反射时,会去那个命名空间里找类,那样是否就好精晓了。

例二:依照有参数的构造器创立对象

Assembly

  1. namespace  TestSpace  
  2. {
  3.   public  class  TestClass
  4.       {
  5.       private  string  _value;
  6.       public  TestClass(string  value)  
  7.     {
  8.       _value=value;
  9.       }
  10.   }
  11. }
  12. Type  t  =  Type.GetType(“TestSpace.TestClass”);
  13. Object[]  constructParms  =  new  object[]  {“hello”};  //构造器参数
  14. TestClass  obj  =  (TestClass)Activator.CreateInstance(t,constructParms);

Assembly的留存让反射变得极度灵巧,当中Assembly.Load不独有能够导入大家引进的程序集(或命名空间)。

复制代码

也得以导入大家未引进程序集的dll。调用格局如下:

把参数依照顺序归入三个Object数组中就可以

System.Reflection.Assembly o = System.Reflection.Assembly.Load("mscorlib.dll");

6、怎样获取格局甚至动态调用方法

Assembly导入了前后相继集后,仍然为能够不凭仗Activator来支援,自个儿就足以创立类。如下:

  1. namespace  TestSpace
  2. {
  3.       public  class  TestClass  {
  4.           private  string  _value;
  5.           public  TestClass()  {
  6.           }
  7.           public  TestClass(string  value)  {
  8.                 _value  =  value;
  9.           }
    1.           public  string  GetValue(  string  prefix  )  {
  10.           if(  _value==null  )
  11.           return  "NULL";
  12.           else
  13.             return  prefix "  :  " _value;
  14.             }
    1.             public  string  Value  {
  15. set  {
  16. _value=value;
  17. }
  18. get  {
  19. if(  _value==null  )
  20. return  "NULL";
  21. else
  22. return  _value;
  23. }
  24.             }
  25.       }
  26. }
Assembly assembly = Assembly.Load("Syntax");
Kiba kiba = (Kiba)assembly.CreateInstance("Syntax.Kiba");

复制代码

一些同学恐怕会顾虑性能,会感觉这么反射,会使程序变慢。

地点是八个大概的类,包含二个有参数的构造器,三个GetValue的法子,三个Value属性,大家得以经过艺术的称号来猎取方法并且调用之,如:

有这种想法的同校,其实你早已经是在过度掌握语法了。这种地点的代码质量其实是可以不用关爱的。

  1. //获取类型音讯
  2. Type  t  =  Type.GetType("TestSpace.TestClass");
  3. //构造器的参数
  4. object[]  constuctParms  =  new  object[]{"timmy"};
  5. //依照项目创设对象
  6. object  dObj  =  Activator.CreateInstance(t,constuctParms);
  7. //获取情势的新闻
  8. MethodInfo  method  =  t.GetMethod("GetValue");
  9. //调用方法的部分标记位,这里的含义是Public何况是实例方法,这也是暗中同意的值
  10. BindingFlags  flag  =  BindingFlags.Public  |  BindingFlags.Instance;
  11. //GetValue方法的参数
  12. object[]  parameters  =  new  object[]{"Hello"};
  13. //调用方法,用贰个object接受重临值
  14. object  returnValue  =  method.Invoke(dObj,flag,Type.DefaultBinder,parameters,null);

那正是说,到底会不会变慢呢?

复制代码

答案是那般的,借使您是使用完全限制名来反射,速度正是千篇生龙活虎律的。假若是反光时,只写了一个类名,那么速度就能够变慢。因为它要遍历全体的命名空间,去找那么些类。

品质与办法的调用千篇一律,我们也能够参照MSDN

即,只要反射时把类的命名空间写全,那么速度就不会慢。

7、动态创立委托
        委托是C#中落实事件的功底,有的时候候不可幸免的要动态的创立委托,实际上委托也是生龙活虎种等级次序:System.Delegate,全部的寄托都以从那么些类派生的
        System.Delegate提供了有的静态方法来动态创立一个寄托,比方二个寄托:

2,函数反射

  1. namespace  TestSpace  {
  2.       delegate  string  TestDelegate(string  value);
  3.       public  class  TestClass  {
  4. public  TestClass()  {
  5.                   }
  6.                   public  void  GetValue(string  value)  {
  7.                           return  value;
  8.                   }
  9.         }
  10. }

函数的反光应用关键是利用类MethodInfo类反射,上面先看下基础应用。

复制代码

public static void ExcuteMethod()
{ 
    Assembly assembly = Assembly.Load("Syntax"); 
    Type type = assembly.GetType("Syntax.Kiba", true, false);
    MethodInfo method =  type.GetMethod("PrintName"); 
    object kiba = assembly.CreateInstance("Syntax.Kiba");
    object[] pmts = new object[] { "Kiba518" };
    method.Invoke(kiba, pmts);//执行方法  
}
public class Kiba
{
    public string Name { get; set; }
    public void PrintName(string name)
    {
        Console.WriteLine(name);
    }
}

利用示例:

大器晚成部分同室第生龙活虎立时刻去大概会有一些不适应,因为相近比比较多类都是豪门不经常常用的。这也不能,因为那是二个晋级的进度,必得经历从面生到熟悉。当您熟知了那样的代码后,就表示你的本事水平又前行了二个台阶。

  1. TestClass  obj  =  new  TestClass();
    1. //获取项目,实际上这里也得以直接用typeof来获得项目
  2. Type  t  =  Type.GetType(“TestSpace.TestClass”);
  3. //成立代理,传入类型、创造代理的靶子以至艺术名称
  4. TestDelegate  method  =  (TestDelegate)Delegate.CreateDelegate(t,obj,”GetValue”);
    1. String  returnValue  =  method(“hello”);

上边疏解一些那个代码。

复制代码

第黄金年代大家导入了命名空间,接着大家收获了该命名空间下Kiba那么些类的项目;接下去大家通过那个体系来获得钦赐名称的函数。


然后我们透过Assembly创立了一个Kiba的实例,接着定义了四个参数的Object数组,因为Kiba类下的函数PrintName只有八个参数,所以,我们只为那几个Object数组增加多个目的[Kiba518]。

别的意气风发篇关于反射的篇章

最后,大家通过method.Invoke来调用那一个函数,由于是反光,所以调用时,必要钦定Kiba类的实例对象和入参。

---------------原来的作品如下------------------

诸有此类,函数的反射就贯彻了。

反射的概念:调查元数据并征集有关它的类型音信的才具。元数据(编写翻译以往的最基本数据单元)正是一大堆的表,当编写翻译程序集只怕模块时,编写翻译器会创制贰个类定义表,二个字段定义表,和叁个主意定义表等。
          System.reflection命名空间饱含的多少个类,允许你反射(深入剖析)那些元数据表的代码   

3,属性反射

System.Reflection.Assembly 
System.Reflection.MemberInfo
System.Reflection.EventInfo
System.Reflection.FieldInfo
System.Reflection.MethodBase
System.Reflection.ConstructorInfo
System.Reflection.MethodInfo
System.Reflection.PropertyInfo
System.Type
以下是上面多少个类的利用办法:
(1)使用Assembly定义和加载程序集,加载在前后相继集清单中列出模块,甚到现在后程序集中查找类型并创制该类型的实例。 
(2)使用Module领会包蕴模块的主次集以致模块中的类等,还是能够收获在模块上定义的具备全局方法或别的特定的非全局方法。 
(3)使用ConstructorInfo掌握构造函数的名称、参数、访谈修饰符(如pulic 或private)和促成详细音信(如abstract或virtual)等。使用Type的GetConstructors或 GetConstructor方法来调用特定的构造函数。 
(4)使用MethodInfo明白方法的名号、再次回到类型、参数、采访修饰符(如pulic 或private)和贯彻详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的措施。 
(5)使用FiedInfo掌握字段的称号、访谈修饰符(如public或private)和促成详细音讯(如static)等,并取得或设置字段值。 
(6)使用伊夫ntInfo掌握事件的称号、事件管理程序数据类型、自定义属性、证明类型和反光类型等,增加或移除事件管理程序。 
(7)使用PropertyInfo领悟属性的名号、数据类型、表明类型、反射类型和只读或可写状态等,获取或安装属性值。 
(8)使用ParameterInfo精通参数的名号、数据类型、是输入参数依旧出口参数,以致参数在章程签字中的地点等。
反射的档次模型:
图片 1
(注:层次间皆今后生可畏对多的涉嫌)

特性反射是用PropertyInfo类来完结,上边看基础的习性反射。

 

public static void ExcuteProperty()
{
    Kiba kiba = new Kiba();
    kiba.Name = "Kiba518";
    object name = ReflectionSyntax.GetPropertyValue(kiba, "Name");
    Console.WriteLine(name); 
} 
public static object GetPropertyValue(object obj, string name)
{
    PropertyInfo property = obj.GetType().GetProperty(name);
    if (property != null)
    {
        object drv1 = property.GetValue(obj, null);
        return drv1;
    }
    else
    {
        return null;
    } 
}

反射的效果:
1、可以运用反射动态地创制项目标实例,将品种绑定到存活对象,或从现有对象中拿走项目
2、应用程序须求在运维时从有个别特定的次第聚集载入三个一定的项目,以便实现有个别任务时能够用到反射。
3、反射重要使用与类库,那几个类库供给精晓叁个类别的定义,以便提供越来越多的功能。

如代码所示,首先大家定义了贰个Kiba的目的,并为Name赋值,然后大家由此GetPropertyValue方法,传递了Kiba对象和要拿走值的性子名称。

选用宗旨:
1、现实应用程序中很罕有应用程序需求接受反射类型
2、使用反射动态绑定供给就义品质
3、有个别元数据消息是不能够通过反射获取的
4、某个反射类型是非常为这么些clr 开荒编写翻译器的支出应用的,所以你要开掘到不是具备的反射类型都是切合各类人的。

GetPropertyValue函数里通过动用PropertyInfo达成了反光。

 

有些同学恐怕会感到,那些很鸡肋,既然已经收获目的,还反射做怎么着,直接拿到就能够了啊。

反射appDomain 的顺序集:

别焦急,大家接下去一同看反射的架构应用。

当你必要反射AppDomain 中隐含的有着程序集,示举个例子下:
static void Main
{
       //通过GetAssemblies 调用appDomain的保有程序集
       foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies())
      {
       //反射当前前后相继集的消息
            reflector.ReflectOnAssembly(assem)
      }
}

反射的架构应用

表达:调用AppDomain 对象的GetAssemblies 方法 将回来三个由System.Reflection.Assembly成分组成的数组。

 框架编写的基本指标之后生可畏,是联合系统秩序。那么哪些是系统秩序呢?

反射单个程序集:

 首先大家看下系统的咬合,系统个日常是由子系统,程序集,类,函数那四有的组成。如下图所示。

地点的艺术讲的是反射AppDomain的保有程序集,我们能够来得的调用此中的二个程序集,system.reflecton.assembly 类型提供了下边二种情势:
1、Load 方法:极力推荐的大器晚成种办法,Load 方法包罗叁个顺序集标识并载入它,Load 将引起CL瑞虎把政策应用到程序集上,先后在大局程序集缓冲区,应用程序基目录和个体路线下边查找该程序集,如若找不到该程序集系统抛出万分
2、LoadFrom 方法:传递三个主次集文件的门道名(包罗扩大名),CLOdyssey会载入您钦点的那些程序集,传递的那几个参数不能够包罗其余关于版本号的音讯,区域性,和公钥音信,若是在钦点路径找不到程序集抛出极其。
3、LoadWithPartialName:永恒不要使用那些形式,因为应用程序不能够明显再在载入的程序集的版本。该方法的天下第一用途是支援那些在.Net框架的测量试验环节使用.net 框架提供的某种行为的客商,那几个点子将最后被撇下不用。

图片 2

在意:system.AppDomain 也提供了意气风发种Load 方法,他和Assembly的静态Load 方法不相像,AppDomain的load 方法是意气风发种实例方法,重临的是三个对程序集的引用,Assembly的静态Load 方发将程序集按值封装发回给发出调用的AppDomain.尽量制止接受AppDomain的load 方法

既然系统由子系统,程序集,类,函数那多少个基础成分构成,那么系统秩序,自然指的正是这两个因素的秩序。而这多少个因素最新生儿窒息生秩序的正是函数了。

应用反射获取类型音信:

很刚烈,任何的等级次序都设有双重的函数,或许成效周边的函数。而干净杜绝这种情状,明显是不恐怕的。那么大家一定要硬着头皮是规划会幸免重复成分的框架了。而反射,就是为此而留存的。

前边说罢了有关程序集的反射,上边在讲一下反光档次模型中的第三个档案的次序,类型反射
贰个总结的施用反射获取类型音信的例子:

反射的框架结构应用

using system;
using sytem.reflection;
class reflecting 
{
       static void Main(string[]args)
       {
             reflecting reflect=new reflecting();//定义一个新的自己类
             //调用多个reflecting.exe程序集

切切实实中的框架因为那样那样的来头,会有蹊跷的设计,所以拘泥于生龙活虎种设计情势是脑血吸虫病的,实战中要出头设计形式一同使用,局地设计有时只取设计格局中黄金年代部分也能够。那样技艺落实项指标量身定制。

             assembly myAssembly =assembly.loadfrom(“reflecting.exe”)
             reflect.getreflectioninfo(myAssembly);//获取反射信息
       }

就此,这里只介绍风流浪漫种实战的架构应用,生机勃勃种接受反射的框架基础结构。上边请框架基础代码。

       //定义一个赢得反射内容的主意
       void getreflectioninfo(assembly myassembly)
       {
             type[] typearr=myassemby.Gettypes();//获取项目
             foreach (type type in typearr)//针对各个门类获取详细音信
            {
                   //获取项目标结构音讯
                  constructorinfo[] myconstructors=type.GetConstructors;

public class Client
{
    public void ExcuteGetNameCommand()
    {
        Proxy proxy = new Proxy();
        GetNameCommand cmd = new GetNameCommand();
        ResultBase rb = proxy.ExcuteCommand(cmd);
    } 
} 
public class Proxy
{
    public ResultBase ExcuteCommand(CommandBase command)
    {
        var result = HandlerSwitcher.Excute(command);
        return result as ResultBase;
    }
}
public class HandlerSwitcher
{
    private const string methodName = "Excute";//约定的方法名
    private const string classNamePostfix = "Handler";//约定的处理Command的类的名称的后缀 
    //获取命名空间的名称
    public static string GetNameSpace(CommandBase command)
    {
        Type commandType = command.GetType();//获取完全限定名
        string[] CommandTypeNames = commandType.ToString().Split('.');
        string nameSpace = "";
        for (int i = 0; i < CommandTypeNames.Length - 1; i  )
        {
            nameSpace  = CommandTypeNames[i];
            if (i < CommandTypeNames.Length - 2)
            {
                nameSpace  = ".";
            }
        } 
        return nameSpace;
    }

    public static object Excute(CommandBase command)
    {
        string fullName = command.GetType().FullName;//完全限定名
        string nameSpace = GetNameSpace(command);//命名空间  
        Assembly assembly = Assembly.Load(nameSpace);
        Type handlerType = assembly.GetType(fullName   classNamePostfix, true, false);
        object obj = assembly.CreateInstance(fullName   classNamePostfix);
        MethodInfo handleMethod = handlerType.GetMethod(methodName);//获取函数基本信息
        object[] pmts = new object[] { command }; //传递一个参数command
        try
        {
            return handleMethod.Invoke(obj, pmts);
        }
        catch (TargetInvocationException tie)
        {
            throw tie.InnerException;
        }
    }
}
public class GetNameCommandHandler
{
    public ResultBase Excute(CommandBase cmd)
    {
        GetNameCommand command = (GetNameCommand)cmd;
        ResultBase result = new ResultBase();
        result.Message = "I'm Kiba518";
        return result;
    }
}
public class GetNameCommand: CommandBase
{  
} 
public class CommandBase
{ 
    public int UserId { get; set; } 

    public string UserName { get; set; } 

    public string ArgIP { get; set; } 
}
public class ResultBase
{ 
    public string Message { get; set; } 
}

                 //获取项指标字段消息
                 fieldinfo[] myfields=type.GetFiedls()

代码中框架相当粗略,首要指标是得以达成一个代理,用于拍卖承接了CommandBase的类的代办。

                 //获取方式信息
                 MethodInfo   myMethodInfo=type.GetMethods();

即,客户端,无论传来什么样的Command,只要它是后续自CommandBase的,这几个代理都会找到呼应的拍卖类,并施行管理,且再次回到结果。

                 //获取属性音信
                 propertyInfo[] myproperties=type.GetProperties

为了更鲜明的接头这段代码,我们得以参见下边那一个流程图。结合了图片在来看代码,架构就能更清楚。

                 //获取事件新闻
                 EventInfo[] Myevents=type.GetEvents;
           }
      }
}
别的三种获得type对象的法子:
1、System.type   参数为字符串类型,该字符串必须钦命项目标完好名称(满含其取名空间)
2、System.type 提供了四个实例方法:GetNestedType,GetNestedTypes
3、Syetem.Reflection.Assembly 类型提供的实例方法是:GetType,GetTypes,GetExporedTypes
4、System.Reflection.Moudle 提供了这几个实例方法:GetType,GetTypes,FindTypes

图片 3

设置反光类型的成员:

这几个大约的框架中,使用了三个概念,叫做约定优先条件,也称得上约定优于配备;喜欢概念的友人能够自动百度。

反射类型的成员即便反射档案的次序模型中最上面的大器晚成层数据。大家得以由此type对象的GetMembers 方法赢得几个门类的成员。借使大家使用的是不带参数的GetMembers,它只回去该项指标公家定义的静态变量和实例成员,大家也能够由此选用带参数的 GetMembers通过参数设置来回到钦赐的门类成员。具体参数参考msdn 中system.reflection.bindingflags 枚举类型的详尽表明。

框架中央银行使的三个约定如下:

例如:
//设置须要再次回到的门类的分子内容
bindingFlags bf=bingdingFlags.DeclaredOnly|bingdingFlags.Nonpublic|BingdingFlags.Public;
foreach (MemberInfo mi int t.getmembers(bf))
{
       writeline(mi.membertype)    //输出钦命的花色成员
}

第二个是,管理Command的类必得后缀名是Command的类名 Handler结尾。

经过反射创设项目标实例:

第二个是,管理Command的类中的管理函数名必需为Excute。

经过反射可以获得程序集的类型,大家就足以凭借猎取的次第集类型来创立该品种新的实例,那也是日前提到的在运维时创立对象完成晚绑定的功效
大家得以经过上面包车型地铁多少个办法达成:
1、System.Activator 的CreateInstance方法。该办法再次来到新对象的引用。具体选取方法参见msdn
2、System.Activator 的createInstanceFrom 与上三个艺术相似,但是要求钦定项目及其程序集
3、System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap
4、System.type的InvokeMember实例方法:这几个方式再次回到一个与传播参数符合的构造函数,并组织该项目。
5、System.reflection.constructinfo 的Invoke实例方法

实质上概念正是供大家使用的,会用就可以;学习的长河中,概念之类的术语,有个影像就可以。

反射类型的接口:

PS:为了阅读方便,那此中的类都集中写在了八个命名空间之下了,假使有想使用这种设计方式的同学,请遵照本人项目所需举办扩张。

假如您想要得到一个档案的次序承继的具备接口集结,能够调用Type的FindInterfaces GetInterface恐怕GetInterfaces。所有那几个点子只可以回来该品种直接接轨的接口,他们不会回去从二个接口继承下来的接口。要想回到接口的基本功接口必得另行调用上述方法。


反射的品质:

如此,大家就因此反射实现了一个要命轻便的框架,通过运用那么些框架,会让代码变的更加的精简。

利用反射来调用类型大概触发方法,也许访谈一个字段只怕性质时clr 须求做越来越多的职业:校验参数,检查权限等等,所以速度是那几个慢的。所以尽大概不要采用反射实行编制程序,对于盘算编写三个动态构造类型(晚绑定)的应用程序,能够采用以下的两种方法开展替代:
1、通过类的后续关系。让该项目从二个编译时可以预知的功底项目派生出来,在运作时生成该品种的叁个实例,将对其的援用放到其基础项指标八个变量中,然后调用该基础项指标虚方法。
2、通过接口完成。在运维时,构建该项指标叁个实例,将对其的引用放到其接口类型的二个变量中,然后调用该接口定义的虚方法。
3、通过委托落成。让该类型达成四个措施,其名称和原型都与八个在编写翻译时就已知的嘱托切合。在运作时先构造该品种的实例,然后在用该措施的对象及称号构造出该信托的实例,接着通过信托调用你想要的措施。这些主意相对与眼下八个点子所作的办事要多一些,成效更低一些。

而为了促成各个模块的精练,反射也将会被封装在各种模块的尾巴部分,所以,反射颠簸不破,就是框架设计的底蕴。

 

反射与风味

村办操作方案:

反射在系统中另一个入眼应用就是与风味的组合使用。

源DLL类:

在一些针锋相投复杂的种类中,难免会遭逢某个风貌,要讲对象中的风流罗曼蒂克部分属性清空,或然要收获对象中的有个别质量赋值。常常大家的达成方式正是手写,贰个一个的赋值。

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Collections;

而使用反射并构成特性,完全能够简化这种复杂操作的代码量。

namespace cn.SwordYang
{

 public partial class ReflectionSyntax
 {
     public void ExcuteKibaAttribute()
     {
         Kiba kiba = new Kiba();
         kiba.ClearName = "Kiba518";
         kiba.NoClearName = "Kiba518";
         kiba.NormalName = "Kiba518";
         ClearKibaAttribute(kiba);
         Console.WriteLine(kiba.ClearName);
         Console.WriteLine(kiba.NoClearName);
         Console.WriteLine(kiba.NormalName);
     }
     public void ClearKibaAttribute(Kiba kiba)
     {
         List<PropertyInfo> plist = typeof(Kiba).GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public).ToList();//只获取Public的属性
         foreach (PropertyInfo pinfo in plist)
         {
             var attrs = pinfo.GetCustomAttributes(typeof(KibaAttribute), false);
             if (null != attrs && attrs.Length > 0)
             { 
                 var des = ((KibaAttribute)attrs[0]).Description; 
                 if (des == "Clear")
                 {
                     pinfo.SetValue(kiba, null); 
                 }
             }
         }
     } 
 } 
 public class Kiba
 {
     [KibaAttribute("Clear")]
     public string ClearName { get; set; }
     [KibaAttribute("NoClear")]
     public string NoClearName { get; set; }
     public string NormalName { get; set; }

 }
 [System.AttributeUsage(System.AttributeTargets.All)]
 public class KibaAttribute : System.Attribute
 {
     public string Description { get; set; }
     public KibaAttribute(string description)
     {
         this.Description = description;
     }
 }

    public class TextClass:System.Web.UI.Page
    {

如上述代码所示, 大家经过反射,将有着KibaAttribute天性的,且描述为Clear的性子,清空了。

public static void RunJs(Page _page, string Source)
        {
            _page.ClientScript.RegisterStartupScript(_page.GetType(), "", "<script type="text/javascript">" Source ";</script>");

本来为了三个属性这么做不值得,但借使贰个目的有74天性格的时候,这么做就值得了。

        }

既然能免去属性的数据,那么自然就足感觉属性赋值。至于何以落到实处反射赋值,相信大家能够闻一知十。

}

反射 性情最广大的风貌

}

反射 特性一同利用,最广大的现象就是用ADO.NET从数据库查询出DataTable的数码,然后将DataTable的数码转变到Model实体类型。

//调用代码

我们在付出中,为了让实体越发充血,往往会对数码实体扩张部分性子和办法。(什么是充血?充血就是充血模型,有野趣的同学能够自行百度询问下,简单说正是为实体加属性和艺术。)

System.Reflection.Assembly ass = Assembly.LoadFrom(Server.MapPath("bin/swordyang.dll")); //加载DLL
            System.Type t = ass.GetType("cn.SwordYang.TextClass");//获得类型
            object o = System.Activator.CreateInstance(t);//创立实例

那么,在用反射,将DataTable转存到Model实体的时候,遍历属性并赋值的时候,就能够多遍历那么两遍。

            System.Reflection.MethodInfo mi = t.GetMethod("RunJs");//得到方式

比如只是二个实体,那么,多遍历一回也没影响。但,倘若是数十万的数码,那这多五回的遍历影响就大了。

            mi.Invoke(o, new object[] { this.Page,"alert('测量试验反射机制')"});//调用方法

而用反射 天性,就能够裁减那些额外遍历次数。

反射机制对应设计情势中的战略格局。

讲了如此多为何不给代码呢?

因为本人觉着,将上边的剧情全精通的同学,应该能够说,已经框架启蒙了。那么,这么些反光 天性的DataTable转数据实体,尽管能团结写出来,就算是框架入门了。所以,这里给大家留下了多个演练的空中。

注意,小编这里说的是框架,并不是架设。

框架与架构的区别是这么的,框架是个名词,而架构是个动词。框架就算很在行了,也不见得足以架构的很好。这一个我们依然要小心区分。

结语

看完了整篇小说,有的同学大概会有毛病,这么生分的PropertyInfo和MethodInfo真的有人会用吗?都以Copy代码,然后使用呢。

答案是,当然有人能够了解应用。反射是架构师的入门基础,任何八个[可以实战]的架构师,都亟待时时到处的能够手写出反射,因为优化框架是他俩的权力和权利。

之所以,对此有所疑虑的伴儿,能够着力演习了,将委托融合血液,是尖端软件工程师的底子,而将反射融合血液,正是架构师的基本功了。

C#语法——元组类型

C#语法——泛型的有余利用

C#语法——await与async的精确性张开方式

C#语法——委托,架构的血流

C#语法——事件,渐渐边缘化的长兄。

C#语法——音信,MVVM的宗旨技术。

我对C#的认知。


注:此小说为原创,迎接转发,请在随笔页面分明地方给出此文链接!
若您感到那篇文章还可以,请点击下右下角的【推荐】,非常谢谢!
生机勃勃旦你认为那篇作品对您具备利于,那就无妨支付宝小小打赏一下吗。 

图片 4

 

本文由pc28.am发布于计算机编程,转载请注明出处:架构师的入门基础

上一篇:力不能支显著标准表达式的品种,职业总计 下一篇:没有了
猜你喜欢
热门排行
精彩图文