C#基础篇——反射

前言

  在探究地球内部的结构中,如何作到在地球表面不用深刻地球内部就能够知道内部的构造呢?其实,向地球发射“地震波”。利用这种方式,能够判断地球放回的状况,大致上,咱们也能够判定地球内部的构造了。编程

  从这个例子中,经过一个对象的外部去了解对象内部的构造,都是利用了波的反射功能。而利用这种原理,在编程程序时,咱们如何也能够实现从对象的外部来了解对象以及程序集内部的结构功能?在.NET中的反射,不只能够实现外部对内部的了解,也同时能够动态建立出对象并执行其中的方法。api

  反射是.NET中的重要机制,经过反射,能够在运行时得到程序或程序集中每个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,便可对每个类型了如指掌。另外我还能够直接建立对象,即便这个对象的类型在编译时还不知道。 数组

开始

 1、使用的命名空间函数

    System.Reflection
    System.Type
    System.Reflection.Assembly性能

2、主要的类this

    System.Type 类--经过这个类能够访问任何给定数据类型的信息。
    System.Reflection.Assembly类--它能够用于访问给定程序集的信息,或者把这个程序集加载到程序中。spa

说明

 1、System.Type类3d

 System.Type类对反射起着核心的做用。它是一个抽象的基类,Type有与每种数据类型对应的派生类,咱们使用这个派生类的对象的方法、字段、属性来查找有关该类型的全部信息。code

表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。对象

从Type中解析类型信息:

 A、判断给定类型的引用的经常使用方式:

1.  使用C# typeof运算符

 Type t = typeof(string);

2. 使用对象GetType()方法

  string s = "i3yuan";
  Type t2 = s.GetType();

3.调用静态Type类的静态方法GetType()

  Type t3 = Type.GetType("System.String");

以上三种方式获取类型Type后,能够应用t来探测string里面的结构

  foreach (MemberInfo mi in t.GetMembers())
  {
       Console.WriteLine("{0}/t{1}", mi.MemberType, mi.Name);
  }

B、Type类属性:

  1.命名空间和类型名

        Name 数据类型名
        FullName 数据类型的彻底限定名(包括命名空间名)
        Namespace 定义数据类型的命名空间名

  2. 类和委托

        Type.IsClass   判断一个类型是否为类或者委托。符合条件的会有普通的类(包括泛型)、抽象类(abstract class)、委托(delegate)

  3. 是否泛型  

        Type.IsGenericType 属性能够判断类或委托是否为泛型类型。

        Type.IsGenericTypeDefinition 属性能够判断Type是不是未绑定参数类型的泛型类型。

        Type.IsConstructedGenericType 属性判断是否能够此Type建立泛型实例。

  4.访问修饰符

        Type.IsPublic 判断该类型是不是公有的

        Type.IsNotPublic

  5.密封类、静态类型、抽象类

        Type.IsSealed 判断该类型是不是密封类,密封类不能被继承

        IsAbstract 指示该类型是不是抽象类型

  6. 值类型

        Type.IsValueType 判断一个 Type 是否为值类型,简单值类型、结构体、枚举,都符合要求。

        Type.IsEnum   判断该类型是不是枚举

        Type.IsPrimitive  判断Type是否为基础类型

  7.接口

        Type.IsInterface    判断该类型是不是接口

  8.数组

        IsArray   判断该类型是不是数组,GetArrayRank() 获取数组的维数。

从Type类解析类型成员结构

一个类由如下一个或多个成员组成:

成员类型 说明
PropertyInfo 类型的属性信息
FieldInfo 类型的字段信息
ConstructorInfo 类型的构造函数信息
MethodInfo 类型的方法
ParameterInfo 构造函数或方法的参数
EventInfo 类型的事件

C、Type类的方法

    public class MySqlHelper
    {
        public MySqlHelper()
        {
            Console.WriteLine("{0}被构造", this.GetType().Name);
        }


        public void Query()
        {
            Console.WriteLine("{0}.Query", this.GetType().Name);
        }
    }

        GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息

                    MySqlHelper dBHelper = new MySqlHelper();
                    Type type = dBHelper.GetType();
                    ConstructorInfo[] constructorInfos= type.GetConstructors();
                    foreach (var item in constructorInfos)
                    {
                        ParameterInfo[] parameterInfos = item.GetParameters();
                        foreach (var info in parameterInfos)
                        {
                            Console.WriteLine("查看:" + info.ParameterType.ToString() + "  " + info.Name);
                        }

                    }

        GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息

        GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息

        MySqlHelper nc = new MySqlHelper();
        Type t = nc.GetType();
        FieldInfo[] fis = t.GetFields();
        foreach (FieldInfo fi in fis)
        {
            Console.WriteLine(fi.Name);
        } 

        GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息

        GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的全部成员的信息

            string n = "i3yuan";
            Type t = n.GetType();
            foreach (MemberInfo mi in t.GetMembers())
            {
                Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name);
            }

        GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息

        MySqlHelper dBHelper= new MySqlHelper();
        Type t = dBHelper.GetType();
        MethodInfo[] mis = t.GetMethods();
        foreach (MethodInfo mi in mis)
        {
            Console.WriteLine(mi.ReturnType+" "+mi.Name);
        }

        GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息

        MySqlHelper dBHelper= new MySqlHelper();
        Type t = dBHelper.GetType();
        PropertyInfo[] pis = t.GetProperties();
        foreach(PropertyInfo pi in pis)
        {
            Console.WriteLine(pi.Name);
        }

  能够调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其余类的Invoke()方法。 

  用反射生成对象,并调用属性、方法和字段进行操做 

        //获取类型信息
        MySqlHelper dbHelper=new MySqlHelper();
        Type type=dbHelper.GetType
        //建立对象实例化
        object DbHelper = Activator.CreateInstance(type);
        //类型转换
        IDBHelper iDBHelper = (IDBHelper)DbHelper;
        //方法调用
        iDBHelper.Query();    

 

2、System.Reflection.Assembly类

   Assembly类能够得到程序集的信息,也能够动态的加载程序集,以及在程序集中查找类型信息,并建立该类型的实例。使用Assembly类能够下降程序集之间的耦合,有利于软件结构的合理化

 1. System.Reflection 

用于访问给定程序集的信息,或者把这个程序集加载到程序中。能够读取并使用metadata

方法调用过程:

1.加载DLL  ; 2. 获取类型信息 ;3. 建立对象类型  4. 类型转换  5. 方法调用

                    Assembly assembly = Assembly.Load("Yuan.DB.MySql");//dll名称无后缀  从当前目录加载  1 加载dll
                    //完整路径的加载  能够是别的目录   加载不会错,可是若是没有依赖项,使用的时候会错
                    Type type = assembly.GetType("Yuan.DB.MySql.MySqlHelper");//2 获取类型信息
                    object oDBHelper = Activator.CreateInstance(type);//3 建立对象
                    //oDBHelper.Query();//oDBHelper是objec不能调用,但实际上方法是有的   编译器不承认  
                    IDBHelper iDBHelper = (IDBHelper)oDBHelper;//4 类型转换
                    iDBHelper.Query();//5 方法调用

方法二:经过程序集的名称反射

                    Assembly assembly = Assembly.Load("Yuan.DB.MySql");//dll名称无后缀  从当前目录加载  1 加载dll
               
                    Type type = assembly.GetType("Yuan.DB.MySql.MySqlHelper");//2 获取类型信息

                    object oDBHelper = Activator.CreateInstance(type);//3 建立对象
                   MethodInfo mi=oDBHelper.GetMethod("Query"); //获取方法
                    mi.Invoke(oDBHelper,null);//5 调用

总结

  1. 做为一个开发人员,在天天都会应用到反射,使用的时候,会反射当前程序的元数据,将全部的方法,类等信息都所有显示出来,以便开发人员使用,大大的提升了效率

  2. 同时反射提升了程序的灵活性和拓展性,下降耦合,动态加载,容许控制和实现任何类的对象。

  3. 固然了,也存在弊端,写起来复杂,也存在性能问题,用于字段和方法接入时要远慢于直接代码。

  参考 文档 和 《C#图解教程》

  注:搜索关注公众号【DotNet技术谷】--回复【C#图解】,可获取 C#图解教程文件

相关文章
相关标签/搜索