学习系列之反射

Posted StrugglingDave

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习系列之反射相关的知识,希望对你有一定的参考价值。

一 反射概述

     反射是一种机制,通过这种机制我们可以知道一个未知类型的类型信息.比如,有一个对象a,这个对象不是我们定义的,也许是通过网络捕捉到的,也许是使用泛型定义的,但我们想知道这个对象的类型信息,想知道这个对象有哪些方法或者属性什么的.甚至我们想进一步调用这个对象的方法.关键是现在我们只知道它是一个对象,不知道它的类型,自然不会知道它有哪些方法等信息.这时我们该怎么办?反射机制就是解决这么一个问题的.通过反射机制我们可以知道未知类型对象的类型信息,并且使用它 

  ·  通过反射可以提供类型信息,从而使得我们开发人员在运行时能够利用这些信息构造和使用对象。 

  ·  反射机制允许程序在执行过程中动态地添加各种功能。

二 反射的核心类:System.Type类

  • 许多支持反射的类都位于System.Reflection命名空间中,他们是.net  Reflection API的一部分,所以在使用的反射的程序中一般都要使用 System.Reflection的命名空间。
  • System. Type类包装了类型,因此是整个反射子系统的核心,这个类中包含了很多属性和方法,使用这些属性和方法可以在运行时得到类型的信息。
  • Type类派生于System.Reflection.MemberInfo抽象类   

      注意: 

  • MemberType属性的返回类型为MemberTypes,这是一个枚举,它定义了用于表示不同成员的类型值。这些值包括:  MemberTypes.Constructor, MemberTypes.Method,     MemberTypes.Field,   MemberTypes.Event,  MemberTypes.Property。因此可以通过检查MemberType属性来确定成员的类型,例如,在MemberType属性的值为MemberTypes.Method时,该成员为方法
  • MemberInfo类还包含两个与特性相关的抽象方法:  

        GetCustomAttributes() :获得与主调对象关联的自定义特性列表。

        IsDefined(): 确定是否为主调对象定义了相应的特性。

        GetCustomAttributesData():返回有关自定义特性的信息(特性稍后便会提到)

        当然除了MemberInfo类定义的方法和属性外,Type类自己也添加了许多属性和方法:如下表(只列出一些常用的,太多了,自己可以转定义Type类看下) 

三 System.Reflection.Assembly类

      通过Assembly可以动态加载程序集,并查询程序集内部信息.Assembly中有三种方法加载程序集:Load,Loadform,LoadFile.

    *如果引用了命名空间,则就直接用Load方法,参数里写上命名空间+类名就可加载。

    *若仅仅知道一个dll文件,则就要用LoadFrom方法,参数里直接填写完整的路径。LoadFrom只能用于加载不同标识的程序集,即唯一的程序集,不能加载标识相同但路径不同的程序集

    *Loadfile,加载指定路径上的程序集文件;与上述两方法不同的是:它不会加载此程序集中引用的其他的程

序集,且不会加载相同标识的程序集。

举例:

      Assembly assembly = Assembly.Load("MyAssembly"); //引用命名空间  
      Assembly assembly2 = Assembly.LoadFrom("D:\\testDll.dll");   
      Assembly dll = Assembly.LoadFile(Environment.CurrentDirectory + "\\\\testDll.dll");                        //通过dll文件去反射其中所有的类型,但不会加载引用的程序集</span>  

三 使用反射

   通过使用Type类定义的方法和属性,我们能够在运行时获得类型的各种具体信息。这是一个非常强大的功能。我们一旦得到类型信息,就可以调用其构造函数,方法,和属性。可见,反射是允许使用编译时不可用的代码的。

  四种关键的反射技术:

1.获取方法的信息

2.调用方法

3.构造对象

4.从程序集中加载类型

四 获取成员的信息

public class RefClass : Object
    {
        private int _test3;
        private int _test1 { get; set; }
        protected int Test2 { get; set; }
        public int Test3 { get; set; }

        private static void Show2()
        {
        }

        public static void Show3()
        {
        }

        public void Show()
        {

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            Func<MemberTypes, string> getType = (x) =>
                {
                    switch (x)
                    {
                        case MemberTypes.Field:
                            {
                                return "字段";
                            }

                        case MemberTypes.Method:
                            {
                                return "方法";
                            }
                        case MemberTypes.Property:
                            {
                                return "属性";
                            }
                        default:
                            {
                                return "未知";
                            }
                    }
                };


            MemberInfo[] mis = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static);

            foreach (MemberInfo mi in mis)
            {
                Console.WriteLine("类型成员的名称{0},类型:{1}", mi.Name,getType(mi.MemberType));
            }
            Console.ReadLine();
        }
    }

五  获取字段的信息

public class RefClass 
    {
        private int _test3;
        public int Test3 { get; set; }


        private int _test1 { get; set; }
        protected int Test2 { get; set; }

        

        private static void Show2()
        {
        }

        public static void Show3()
        {
        }

        public void Show()
        {

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Type t = typeof(RefClass);

            RefClass rc = new RefClass();
            rc.Test3 = 3;

            FieldInfo[] fis = t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static);

            foreach (FieldInfo  fi in fis)
            {
                fi.SetValue(rc,100);
                Console.WriteLine("字段成员的名称{0},字段类型:{1},rc中的值{2}", fi.Name,fi.FieldType,fi.GetValue(rc));
            }
            Console.ReadLine();
        }
}                             

六 获取属性的信息

public class RefClass
    {
        private int _test3;
        public int Test3 { get; set; }


        private int _test1 { get; set; }
        protected int Test2 { get; set; }



        private static void Show2()
        {
        }

        public static void Show3()
        {
        }

        public void Show()
        {

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Type t = typeof(RefClass);

            RefClass rc = new RefClass();
            PropertyInfo[] fis = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static);
            foreach (PropertyInfo fi in fis)
            {
                MethodInfo getinfo = fi.GetGetMethod(true);
                 Console.WriteLine("get方法的名称{0}  返回值类型:{1}  参数数量:{2}  MSIL代码长度:{3} 局部变量数量:{4}", 
                     getinfo.Name, 
                     getinfo.ReturnType.ToString(),
                     getinfo.GetParameters().Count(),
                     getinfo.GetMethodBody().GetILAsByteArray().Length, 
                     getinfo.GetMethodBody().LocalVariables.Count);

                 MethodInfo setinfo = fi.GetSetMethod(true);
                 Console.WriteLine("set方法的名称{0}  返回值类型:{1}  参数数量:{2}  MSIL代码长度:{3} 局部变量数量:{4}", 
                     setinfo.Name, 
                     setinfo.ReturnType.ToString(),
                     setinfo.GetParameters().Count(),
                     setinfo.GetMethodBody().GetILAsByteArray().Length,
                     setinfo.GetMethodBody().LocalVariables.Count);
 
                 setinfo.Invoke(rc, new object[] { 123 }); //设置值

                 object obj = getinfo.Invoke(rc, null);
                 Console.WriteLine("方法名:{0}  内部值:{1}", fi.Name, obj);//读出值
            }
            Console.ReadLine();
        }
    }

七 获取方法的信息

BindingFlags是一个枚举,枚举值有(很多只列出5个吧):

  1. DeclareOnly:仅获取指定类定义的方法,而不获取所继承的方法;
  2. Instance:获取实例方法
  3. NonPublic: 获取非公有方法
  4. Public: 获取共有方法
  5. Static:获取静态方法
public class RefClass
    {
        private int _test3;
        private int _test1 { get; set; }
        protected int Test2 { get; set; }
        public int Test3 { get; set; }

        private static void Show2()
        {

        }

        public static string Show3(string s)
        {
            int b;
            int c;
            return s;
        }
        public string Show(string s)
        {
            string a; 
return s; } } class Program { static void Main(string[] args) { RefClass rc = new RefClass(); Type t = typeof(RefClass); MethodInfo[] mis = t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static); foreach (MethodInfo mi in mis) { if ((mi.GetParameters().Count() > 0) && (mi.GetParameters()[0].ParameterType == typeof(string))) { var a = new[] { "123" }; object obj = mi.Invoke(rc, a); MethodBody mbody = mi.GetMethodBody(); Console.WriteLine("拥有参数的方法名:{0} 返回值类型:{1} 参数1类型:{2} 参数1名称:{3} 方法调用后返回的值:{4}", mi.Name, mi.ReturnType.ToString(), mi.GetParameters()[0].ParameterType.ToString(), mi.GetParameters()[0].Name, obj.ToString()); } else { MethodBody mbody = mi.GetMethodBody(); Console.WriteLine("没有参数的方法名:{0} 返回值类型:{1}", mi.Name, mi.ReturnType.ToString()); } } Console.ReadKey(); } }

八 动态创建对象

class MyClass
    {
        int x;
        int y;
        public MyClass(int i)
        {
            x = y + i;
        }
        public MyClass(int i, int j)
        {
            x = i;
            y = j;
        }
        public int sum()
        {
            return x + y;
        }
    }
    class Program
    {
        static void Main()
        {
           Type t=typeof(MyClass);

           int val;
           ConstructorInfo[] ci = t.GetConstructors(); //获取构造函数的列表

           int x;//记录构造函数的个数
           for (x = 0; x < ci.Length; x++)
           {
               ParameterInfo[] pi = ci[x].GetParameters();
               if (pi.Length == 2)
                   break;
           }
           if (x == ci.Length)
           {
               return;
           }


           object[] consargs = new object[2];
           consargs[0] = 10;
           consargs[1] = 20;
           object reflectOb = ci[x].Invoke(consargs);//实例化一个这个构造函数有两个参数的类型对象,如果参数为空,则为null

           //实例化后,调用MyClass中的方法
           MethodInfo[] mi = t.GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
           foreach (MethodInfo m in mi)
           {
               if (m.Name.Equals("sum", StringComparison.Ordinal))
               {
                   val = (int)m.Invoke(reflectOb, null);  //由于实例化类型对象的时候是用的两个参数的构造函数,所以这里返回的结构为30
                   Console.WriteLine(" sum is " + val);  //输出 sum is 30
               }
           }
           Console.ReadKey();
        }
    }

以上是关于学习系列之反射的主要内容,如果未能解决你的问题,请参考以下文章

《C#零基础入门之百识百例》(一百)反射详解 -- 检索特性

《C#零基础入门之百识百例》(一百)反射详解 -- 检索特性

细说java系列之反射

java反射系列五之获取类的完整结构

java反射系列四之创建运行时类的对象

java 反射代码片段