• C#秘密武器之反射——基础篇


    先来一段有用的反射代码

    namespace Calculator 
    { 
        public interface Iwel 
        { 
            String Print(); 
        } 
    }  
      
    namespace Calculator 
    { 
        public class Arithmetic:Iwel 
        { 
            /// <summary> 
            /// 没有带参数的构造函数 
        /// </summary> 
            public Arithmetic() 
            {} 
            public Arithmetic(int num1, int num2) 
            { 
                _num1 = num1; 
                _num2 = num2; 
            } 
            private int _num1; 
      
            public int Num1 
            { 
                get { return _num1; } 
                set { _num1 = value; } 
            } 
            private int _num2; 
      
            public int Num2 
            { 
                get { return _num2; } 
                set { _num2 = value; } 
            } 
            public String Add(int num1, int num2) 
            { 
                Console.WriteLine("{0}+{1}={2}", num1, num2, num1 + num2); 
                return "Add(int num1,int num2)方法是一个公有的带参数的方法"; 
            } 
            private string Add() 
            { 
                return "Add()方法是一个私有的不传参数的方法"; 
            } 
            private void Subtration(int num1, int num2) 
            { 
                Console.WriteLine("{0}-{1}={2}+Subtration(int num1,int num2)" + "方法是一个私有的带有参数的方法 ",num1,num2,num1-num2); 
            } 
            public static void Multiplication(int num1, int num2) 
            { 
                Console.WriteLine("{0}*{1}={2} Multiplication(int num1,int num2)"+"是一个公有的带参数的静态方法",num1,num2,num1+num2); 
            } 
            private static void Multiplication() 
            { 
                Console.WriteLine("Multiplication()是一个公有的带参数的静态方法"); 
      
            } 
            public String Writ() 
            { 
                return "Writ() 是一个公有的不带参数的方法"; 
            } 
            #region Iwel 成员 
      
            public string Print() 
            { 
                return "欢迎您使用接口!"; 
            } 
      
            #endregion 
      
               
        } 
    } 
      
      
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.Reflection; 
      
      
    namespace BassLib 
    { 
        class Program 
        { 
              
             delegate void TestDelegate(int num1, int num2); 
             static void Main(string[] args) 
             { 
                 Assembly assembly = Assembly.Load("Calculator");//加载程序集 
                 Console.WriteLine("得到Calculator.dll中的所有类"); 
                 Console.WriteLine("***********************************"); 
                 foreach (Type myType in assembly.GetTypes()) 
                 { 
                     //得到Calculator.dll中所有的类 
                     Console.WriteLine(myType.Name + "是Calculator命中空间下的类"); 
                 } 
                 Console.WriteLine(" +++++++++++++++++++++++++++++++++++++"); 
                 Console.WriteLine("得到Calculator.dll中的模块集"); 
                 Module[] modules = assembly.GetModules();//得到Calculator.dll中的模块集合 
                 foreach (Module module in modules) 
                 { 
                     Console.WriteLine(module.Name + "是Calculator中的一个模块 "); 
                 } 
                 Console.WriteLine("*********************************************"); 
                 Console.WriteLine(""); 
      
                 Type type = typeof(Calculator.Arithmetic);//得到具体的类型 
                 Console.WriteLine("具体的类型是" + type.Name); 
                 Console.WriteLine(" {0}是不是public类型:{1}", type, type.IsPublic); 
                 Console.WriteLine("{0}是不是private类型:{1}", type, type.IsNotPublic); 
      
                 Console.WriteLine("*********************************************"); 
                 Console.WriteLine(""); 
                 PropertyInfo[] memberInfo = type.GetProperties();//得到类中的属性 
                 foreach (PropertyInfo var in memberInfo) 
                 { 
                     Console.WriteLine(type + "类的属性有" + var.Name); 
                 } 
                 Console.WriteLine("**********************************************"); 
                 Console.WriteLine(""); 
      
                 Type[] t = type.GetInterfaces();//得到接口 
                 foreach (Type var in t) 
                 { 
                     Console.WriteLine(var.Name + "是Calculator.dll中的接口"); 
                 } 
                 Console.WriteLine("*****************************************"); 
                 Console.WriteLine(""); 
      
                 Console.WriteLine("方法的返回类型,方法传参的类型"); 
                 //查找私有的方法 
                 MethodInfo[] method = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic); 
                 foreach (MemberInfo var in method) 
                 { 
                     Console.WriteLine("私有方法: 方法名 ={0} 方法的信息={1}", var.Name, var); 
                 } 
                 //查找公有方法 
                 MethodInfo[] methodpublic = type.GetMethods(BindingFlags.Instance | BindingFlags.Public); 
                 foreach (MethodInfo var in methodpublic) 
                 { 
                     Console.WriteLine("公有方法:方法名={0} 方法的信息={1}", var.Name, var); 
                 } 
                 //查找公有的静态方法 
                 MethodInfo[] mathodstatic = type.GetMethods(BindingFlags.Public | BindingFlags.Static); 
                 foreach (MethodInfo var in mathodstatic) 
                 { 
                     Console.WriteLine("公有静态方法: 方法名={0} 方法的信息 ={1}", var.Name, var); 
                 } 
                 //查找私有静态方法 
                 MethodInfo[] methodprivartstatic = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static); 
                 foreach (MethodInfo var in methodprivartstatic) 
                 { 
                     Console.WriteLine("私有静态方法: 方法名={0} 方法的信息={1}", var.Name, var); 
                 } 
                 Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++"); 
                 Console.WriteLine("这是一个构造方法的形式 "); 
      
                 ConstructorInfo[] con = type.GetConstructors();//获得构造函数的形式 
                 foreach (ConstructorInfo var in con) 
                 { 
                     Console.WriteLine(var); 
                 } 
                 Console.WriteLine("_________________________________"); 
                 object obj = Activator.CreateInstance(type, null);//创建了一个不带参数的实例 
                 //公有非静态带参数和返回参数的方法的调用它 
                 MethodInfo men1 = type.GetMethod("Add"); 
                 Console.WriteLine("调用{0}方法 ", men1); 
                 object[] nums1 = { 5, 4 };//参数 
                 Console.WriteLine(men1.Invoke(obj, nums1)); 
      
                 Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); 
                 //私有的非静态方法的调用 
                 MethodInfo men2 = type.GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic); 
                 Console.WriteLine(men2.Invoke(obj, null)); 
                 Console.WriteLine("**********************************"); 
                 //公有的静态带参数的方法的调用 
                 MethodInfo men3 = type.GetMethod("Multiplication", BindingFlags.Public | BindingFlags.Static); 
                 object[] nums2 = { 5, 6 }; 
                 men3.Invoke(null, nums2); 
                 Console.WriteLine("*****************"); 
                 //私有的静态的 
                 MethodInfo men4 = type.GetMethod("Multiplication", BindingFlags.NonPublic | BindingFlags.Static); 
                 men4.Invoke(null, null); 
                 Console.WriteLine("************************"); 
                 //动态创建一个委托 
                 Console.WriteLine("动态创建委托"); 
                 TestDelegate dele = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "Subtration"); 
                 dele(9, 3); 
             } 
        } 
    } 
    View Code

    反射的几种基本类型

    1、System.Reflection.Assembly类

         通过Assembly可以动态加载程序集,并查看程序集的内部信息,其中最常用的就是Load()这个方法。

         Assembly assembly=Assembly.Load("MyAssembly");

         利用Assembly的object CreateInstance(string) 方法可以反射创建一个对象,参数0为类名。

    2、System.Type类

         Type是最常用到的类,通过Type可以得到一个类的内部信息,也可以通过它反射创建一个对象。一般有三个常用的方法可得到Type对象。

    1. 利用typeof() 得到Type对象

      Type type=typeof(Example);

    2. 利用System.Object.GetType() 得到Type对象

      Example example=new Example();

      Type type=example.GetType();

    3. 利用System.Type.GetType() 得到Type对象

      Type type=Type.GetType("MyAssembly.Example",false,true);

      注意参数0是类名,参数1表示若找不到对应类时是否抛出异常,参数1表示类名是否区分大小写

       例子:

       我们最常见的是利用反射与Activator结合来创建对象:

    Assembly assembly= Assembly.Load("MyAssembly");
    Type type=assembly.GetType("Example");
    object obj=Activator.CreateInstance(type);

    3、反射方法

        1.通过 System.Reflection.MethodInfo能查找到类里面的方法

        代码:

    Type type=typeof(Example);
    MethodInfo[] listMethodInfo=type.GetMethods();
    foreach(MethodInfo methodInfo in listMethodInfo)
    Cosole.WriteLine("Method name is "+methodInfo.Name);

        2.我们也能通过反射方法执行类里面的方法

       代码:

    Assembly assembly= Assembly.Load("MyAssembly");
    Type type=assembly.GetType("Example");
    object obj=Activator.CreateInstance(type);
    MethodInfo methodInfo=type.GetMethod("Hello World");  //根据方法名获取MethodInfo对象
    methodInfo.Invoke(obj,null);  //参数1类型为object[],代表Hello World方法的对应参数,输入值为null代表没有参数

    4、反射属性

       1.通过 System.Reflection.PropertyInfo 能查找到类里面的属性

         常用的方法有GetValue(object,object[]) 获取属性值和 SetValue(object,object,object[]) 设置属性值

       代码:

    Type type=typeof(Example);
    PropertyInfo[] listPropertyInfo=type.GetProperties();
    foreach(PropertyInfo propertyInfo in listPropertyInfo)
    Cosole.WriteLine("Property name is "+ propertyInfo.Name);

       2.我们也可以通过以下方法设置或者获取一个对象的属性值

       代码:

    Assembly assembly=Assembly.Load("MyAssembly");
    Type type=assembly.GetType("Example");
    object obj=Activator.CreateInstance(type);
    PropertyInfo propertyInfo=obj.GetProperty("Name");    //获取Name属性对象
    var name=propertyInfo.GetValue(obj,null);            //获取Name属性的值
    PropertyInfo propertyInfo2=obj.GetProperty("Age");    //获取Age属性对象
    propertyInfo2.SetValue(obj,34,null);                  //把Age属性设置为34

    5、反射字段

        通过 System.Reflection.FieldInfo 能查找到类里面的字段

        它包括有两个常用方法SetValue(object ,object )和GetValue(object)  因为使用方法与反射属性非常相似,在此不再多作介绍

    6、反射特性

       通过System.Reflection.MemberInfo的GetCustomAttributes(Type,bool)就可反射出一个类里面的特性,以下例子可以反射出一个类的所有特性

       代码:

    Type type=typeof("Example");
    object[] typeAttributes=type.GetCustomAttributes(false);       //获取Example类的特性
    foreach(object attribute in typeAttributes)
    Console.WriteLine("Attributes description is "+attribute.ToString());

       通过下面例子,可以获取Example类Name属性的所有特性

       代码:

    public class Example
       {
             [DataMemberAttribute]
             publics string Name
              {get;set;}
            ..................
        }
    
        Type type = typeof(Example);        
        PropertyInfo propertyInfo=type.GetProperty("Name");    //获取Example类的Name属性
        foreach (object attribute in propertyInfo.GetCustomAttributes(false))        //遍历Name属性的所有特性
      Console.WriteLine(“Property attribute: "+attribute.ToString());

    7、反射成员

    我们先考虑一下对于一个类型Type,可能会包含什么类型,常见的有字段、属性、方法、构造函数、接口、嵌套类型等。MemberInfo 类代表着 Type的成员类型,值得注意的是Type类本身又继承自MemberInfo类,理解起来并不困难,因为一个类型经常也是另一类型的成员。Type类提供 GetMembers()、GetMember()、FindMember()等方法用于获取某个成员类型。

    我们再添加一个方法 MemberExplore(),来查看一个类型的所有成员类型。

    namespace Demo
    {
        class SimpleExplore
        {
            static void Main(string[] args)
            {
                MemberExplore(typeof(DemoClass));
            }
     
            public static void MemberExplore(Type t)
            {
                StringBuilder sb = new StringBuilder();
                MemberInfo[] memberInfo = t.GetMembers();
                sb.Append("查看类型 " + t.Name + "的成员信息:
    ");
                foreach (MemberInfo mi in memberInfo)
                {
                    sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "
    ");
                }
                Console.WriteLine(sb.ToString());
            }
        }
    }

    产生的输出如下:

    image

    我们使用了GetMembers()方法获取了成员信息的一个数组,然后遍历了数组,打印了成员的名称和类型。如同我们所知道的:Name属性在编译后成为了get_Name()和set_Name()两个独立的方法;myEvent事件的注册(+=)和取消注册(-=)分别成为了add_myEvent()和remove_myEvent方法。同时,我们发现私有(private)字段name 没有被打印出来,另外,基类System.Object的成员GetType()和Equals()也被打印了出来。

    有的时候,我们可能不希望查看基类的成员,也可能希望查看私有的成员,此时可以使用GetMembers()的重载方法,传入BindingFlags 位标记参数来完成。BindingFlags位标记对如何获取成员的方式进行控制(也可以控制如何创建对象实例,后面会说明)。对于本例,如果我们想获取所有的公有、私有、静态、实例成员,那么只需要这样修改GetMembers()方法就可以了。

    public static void MemberExplore(Type t)
            {
                StringBuilder sb = new StringBuilder();
                //MemberInfo[] memberInfo = t.GetMembers();
                MemberInfo[] memberInfo = t.GetMembers(BindingFlags.Public | BindingFlags.Static
                    | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                sb.Append("查看类型 " + t.Name + "的成员信息:
    ");
                foreach (MemberInfo mi in memberInfo)
                {
                    sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "
    ");
                }
                Console.WriteLine(sb.ToString());
            }

    此时的输出如下:

    image

    可以看到,继承自基类 System.Object 的方法都被过滤掉了,同时,打印出了私有的 name, myEvent 等字段。

    现在如果我们想要获取所有的方法(Method),那么我们可以使用 Type类的FindMembers()方法:

    public static void MemberExplore(Type t)
            {
                StringBuilder sb = new StringBuilder();
     
                //MemberInfo[] memberInfo = t.GetMembers();
     
                //MemberInfo[] memberInfo = t.GetMembers(BindingFlags.Public | BindingFlags.Static
                //    | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
     
                MemberInfo[] memberInfo = t.FindMembers(MemberTypes.Method, // 说明查找的成员类型为 Method 
                                        BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic
                                        | BindingFlags.Instance | BindingFlags.DeclaredOnly, Type.FilterName, "*");
     
                sb.Append("查看类型 " + t.Name + "的成员信息:
    ");
                foreach (MemberInfo mi in memberInfo)
                {
                    sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "
    ");
                }
                Console.WriteLine(sb.ToString());
            }

    Type.FilterName 返回一个MemberFilter类型的委托,它说明按照方法名称进行过滤,最后一个参数“*”,说明返回所有名称(如果使用“Get*”,则会返回所有以Get开头的方法)。

    现在的输出如下:

    image

    MemberInfo 类有两个属性值得注意,一个是DeclaringType,一个是 ReflectedType,返回的都是Type类型。DeclaredType 返回的是声明该成员的类型。比如说,回顾我们之前的一段代码:

    MemberInfo[] members = typeof(DemoClass).GetMembers();

    它将返回所有的公有成员,包括继承自基类的Equals()等方法,对于Equals()方法来说,它的 DeclaringType 返回的是相当于 typeof(Object) 的类型实例,因为它是在 System.Object中被定义的;而它的ReflectedType 返回的则是相当于 typeof(DemoClass) 类型实例,因为它是通过 DemoClass 的类型实例被获取的。

  • 相关阅读:
    线程生命周期
    java集合源码分析几篇文章
    Java中的equals和hashCode方法详解
    java集合(一)
    volatile和synchronized实现内存可见性的区别
    动态代理的原理
    过滤器的使用
    pageBean的实体类
    FindUserByPageServlet
    用户信息系统_serviceImpl
  • 原文地址:https://www.cnblogs.com/WeiGe/p/4202626.html
Copyright © 2020-2023  润新知