实例总结C#反射基础知识

来源:互联网 发布:js 除法 编辑:程序博客网 时间:2024/06/14 01:08
本文中部分内容参考自:

1. Pro C# with .NET 3.0, Special Edition

2. .Net 中的反射(序章) - Part.1

一、基本概念

反射:反射是一个运行库类型发现的过程。 通过反射可以得到一个给定程序集所包含的所有类型的列表,这个列表包括给定类型中定义的方法、字段、属性和事件。也可以动态的发现一组给定类支持的借口、方法的参数和其他相关信息如基类、命名空间、数据清单等。
  
二、命名空间      
  
    1.System.Reflection命名空间内的各类型

            (1)Assembly    通过它可以加载、了解和操纵一个程序集
              (2) AssemblyName 通过它可以找到大量隐藏在程序集的身份中的信息,如版本信息、区域信息等
              (3) EventInfo  事件的信息
              (4) FieldInfo  字段的信息
              (5) MethodInfo  方法的信息
              (6) ParameterInfo  参数的信息
              (7)PropertyInfo  属性的信息
              (8) MemberInfo  是抽象基类,为  EventInfo、FieldInfo 、MethodInfo、PropertyInfo等类型定义了公共的行为。    
              (9) Module 用来访问带有多文件程序集的给定模块  
      
      2.System.Type类 

        System.Type支持的成员可以分为这样几类
              (1) Is***  用来检查一个类型的元数据,如IsAbstract、IsClass、IsValueType等等
              (2) Get*** 用来从类型得到指定项目,如GetEvent()得到类型的一个指定的事件(EventInfo)。 另外,这些方法都有一个单数版本和一个复数版本。如GetEvent()对应有一个复数版            本GetEvents(), 该方法返回一个相关的EventInfo数组 
                (3) FindMembers()  根据查询条件返回一个MemberInfo类型的数组
                (4)GetType()  该静态方法根据一个字符串名称返回一个Type实例
                (5)InvokeMember()  对给定项目进行晚期绑定

      3.得到一个Type类型实例的三种方法(因为Type是一个抽象类,所以不能直接使用new关键字创建一个Type对象)

                (1) 使用System.Object.GetType()
                                    e.g:    Person pe=new Person();  //---------定义pe为person类的一个对象 
                                              Type t=pe.GetType(); 

                (2)使用System.Type.GetType()静态方法,参数为类型的完全限定名
                                    e.g:    Type t=Type.GetType("Entity.Person");
                                              该方法被重载,允许指定两个布尔类型的参数,一个用来控制当前类型不能找到时是否抛出异常,
                        另一个用来指示是否区分字符串大小写                        
                                    e.g:    Type t=Type.GetType("Entity.Person",false,true);
                                注意到传入的字符串并没有包含类型所在的程序集信息,此时该类型便被认为是定义在当前执行的程序集中的。
                                要得到一个外部私有程序集的类型元数据时,字符串参数必须使用类型完全限定名加上类型所在程序集的友好名字
                        e.g:  Type t=Type.GetType("Entity.Person","Entity");//------"Entity"即为类型所在程序集的友好名字 
                            嵌套类型:传入的字符串可以指定一个+标记来表示一个嵌套类型,如希望得到一个嵌套在person类中的枚举类型City的类型信息,
                          则可以这样  e.g:  Type t=Type.GetType("Entity.person+City");

                  (3) 使用typeof运算符        e.g:  Type  t=typeof(person);
                  
                  三种方法的比较:使用第一种方法必须先建立一个实例,而后两种方法不必先建立实例。

                  但使用typeof运算符仍然需要知道类型的编译时信息,而使用System.Type.GetType()静态方法

                  不需要知道类型的编译时信息,所以是首选方法。


下面是一个实例,简单的运用了前面介绍的知识,实现了对一个Type对象的反射,包括反射其所有可见字段、方法、属性、事件。反射类型的基本属性。并将其中一个方法的详细信息列了出来

【源代码】
  1.   1using System;
  2.   2using System.Collections.Generic;
  3.   3using System.Linq;
  4.   4using System.Text;
  5.   5using System.Reflection;
  6.   6
  7.   7using System.Collections; //--------要实现IEnumerable接口则必须制定该命名空间
  8.   8
  9.   9
  10. 10namespace Exercise
  11. 11{
  12. 12    public class BasePerson //-------------假设一个基类,定义了一个公共方法和一个私有方法
  13. 13    {
  14. 14        public void BasePublic()
  15. 15        {
  16. 16        }
  17. 17
  18. 18        private void BasePrivate()
  19. 19        {
  20. 20        }
  21. 21    
  22. 22    };
  23. 23
  24. 24
  25. 25    //Person类实现了接口IEnumerable,使得类中定义的Array数组能够使用foreach枚举
  26. 26    public class Person :BasePerson, IEnumerable 
  27. 27    {
  28. 28        private string name = "林田惠"; //---姓名
  29. 29        public  int age=20;    //---年龄
  30. 30
  31. 31        Array children=null;//---子女数组
  32. 32
  33. 33        Person()
  34. 34        {
  35. 35        }
  36. 36
  37. 37        Person(string a,int b)
  38. 38        {
  39. 39            Name = a;
  40. 40            Age = b;
  41. 41        }
  42. 42
  43. 43    
  44. 44        public string Name 
  45. 45        {
  46. 46            get { return name; }
  47. 47            set { }
  48. 48        }
  49. 49      
  50. 50        public int Age
  51. 51        {
  52. 52            get { return age; }
  53. 53            set { }
  54. 54        }
  55. 55
  56. 56        public void AddAge()//---自增一岁的方法
  57. 57        {
  58. 58            Age+=1;
  59. 59        }
  60. 60
  61. 61        
  62. 62        public delegate void PersonNameHandler(string x);
  63. 63        public event PersonNameHandler OnChangeName; //------定义了一个改变姓名的事件
  64. 64        
  65. 65        public void ChangeName(string nam)//---改名的方法
  66. 66        {
  67. 67            Name = nam;
  68. 68        }
  69. 69
  70. 70        public void  ChangeNameAndAddAge(string name,int age)//------具有两个参数的方法,用来演示反射具体方法的详细情况
  71. 71        {
  72. 72            this.Name = name;
  73. 73            this.Age += age;
  74. 74        }
  75. 75
  76. 76        public IEnumerator GetEnumerator()//---实现接口
  77. 77        {
  78. 78            return children.GetEnumerator();
  79. 79        }
  80. 80
  81. 81    }
  82. 82
  83. 83  
  84. 84
  85. 85    public class Program
  86. 86    {
  87. 87        
  88. 88        
  89. 89        构建自定义元数据查看器#region 构建自定义元数据查看器
  90. 90
  91. 91        //-------------显示传入类型拥有的方法名称
  92. 92        public static void ListMethods(Type t)
  93. 93        {
  94. 94            Console.WriteLine("\n该类型的所有方法:");
  95. 95            MethodInfo[] mi = t.GetMethods();
  96. 96            foreach (MethodInfo  m in mi)
  97. 97            {
  98. 98                Console.WriteLine("\t方法名:{0}",m.Name);
  99. 99            }
  100. 100        }
  101. 101
  102. 102
  103. 103        //-------------显示一个方法的所有参数信息
  104. 104        public static void ListParameters(MethodInfo m)
  105. 105        {
  106. 106            ParameterInfo[] pi = m.GetParameters();
  107. 107            foreach (ParameterInfo  p in pi)
  108. 108            {
  109. 109                Console.WriteLine("参数名:{0}\t参数类型:{1}",p.Name,p.ParameterType); 
  110. 110            }
  111. 111        }
  112. 112
  113. 113
  114. 114        //-------------显示一个特定方法的详细情况
  115. 115        public static void ListMethodDetail(Type t, string MethodName)
  116. 116        {
  117. 117            MethodInfo m = t.GetMethod(MethodName);
  118. 118            Console.WriteLine("\n显示方法详情\n方法名称:{0}", MethodName);
  119. 119            Console.WriteLine("方法返回值类型:{0}", m.ReturnType.FullName);
  120. 120            ListParameters(m);
  121. 121            
  122. 122        }
  123. 123
  124. 124        //------------显示传入类型拥有的字段名称
  125. 125        public static void ListFields(Type t)
  126. 126        {
  127. 127            Console.WriteLine("\n该类型的所有字段:");
  128. 128            FieldInfo [] fi = t.GetFields();
  129. 129            foreach (FieldInfo f in fi )
  130. 130            {
  131. 131                Console.WriteLine("\t字段名:{0}", f.Name);
  132. 132            }
  133. 133        }
  134. 134
  135. 135        //------------显示传入类型拥有的属性名称
  136. 136        public static void ListProperties(Type t)
  137. 137        {
  138. 138            Console.WriteLine("\n该类型的所有属性:");
  139. 139            PropertyInfo[] pi = t.GetProperties();
  140. 140            foreach (PropertyInfo  p in pi)
  141. 141            {
  142. 142                Console.WriteLine("\t属性名:{0}", p.Name);
  143. 143            }
  144. 144        }
  145. 145
  146. 146
  147. 147        //------------显示传入类型拥有的基类名称
  148. 148        public static void ListInterFaces(Type t)
  149. 149        {
  150. 150            Console.WriteLine("\n该类型的所实现的接口:");
  151. 151            Type[] ii = t.GetInterfaces();  //-----------对GetInterfaces()的调用返回一个 Type类型 的数组(说明其实接口也是一种类型)
  152. 152            foreach (Type  p in ii)
  153. 153            {
  154. 154                Console.WriteLine("\t接口名:{0}", p.Name);
  155. 155            }
  156. 156        }
  157. 157
  158. 158        //------------显示传入类型拥有的属性名称
  159. 159        public static void ListEvents(Type t)
  160. 160        {
  161. 161            Console.WriteLine("\n该类型的所有事件名:");
  162. 162            EventInfo [] ei = t.GetEvents();
  163. 163            foreach (EventInfo e in ei )
  164. 164            {
  165. 165                Console.WriteLine("\n事件名:{0}", e.Name);
  166. 166            }
  167. 167        }
  168. 168
  169. 169        //------------各种其他信息
  170. 170        public static void ListOtherInfo(Type t)
  171. 171        {
  172. 172            Console.WriteLine("基类名称:{0}",t.BaseType);
  173. 173            Console.WriteLine("基类的基类的名称:{0}", t.BaseType.BaseType);
  174. 174            Console.WriteLine("是一个类吗?:{0}", t.IsClass);
  175. 175            Console.WriteLine("是一个抽象类吗?:{0}", t.IsAbstract);
  176. 176        }
  177. 177
  178. 178
  179. 179    #endregion
  180. 180
  181. 181        public static void Main(string[] args)
  182. 182        {
  183. 183
  184. 184            Console.WriteLine("----------------------------------------------------------------");
  185. 185
  186. 186            Type t = Type.GetType("Exercise.Person");//-------Person类的完全限定名为"Exercise.Person"
  187. 187            
  188. 188            ListOtherInfo(t);//反射其他一些信息    
  189. 189            ListFields(t);//反射字段
  190. 190            ListProperties(t);//反射属性
  191. 191            ListInterFaces(t);//反射接口
  192. 192            ListEvents(t);//反射事件
  193. 193            ListMethodDetail(t, "ChangeNameAndAddAge");//反射一个特定方法的详细信息
  194. 194            ListMethods(t);//反射方法
  195. 195            
  196. 196            
  197. 197            Console.ReadLine();  
  198. 198        }
  199. 199    }
  200. 200}
  201. 201
  202. 202
复制代码
【实现效果】



【总结】结合源代码和运行效果,总结如下

            1.Name属性在编译后成为了get_Name()和set_Name()两个独立的方法
            2.OnChangeName事件的注册(+=)和取消注册(-=)分别成为了add_ OnChangeName ()和remove_ OnChangeName方法
            3.私有(private)字段name 没有被打印出来
            4.基类的基类System.Object的成员GetType()和Equals()也被打印了出来,基类的共有方法也被打印出来
原创粉丝点击