.NET基础 (17)反射

反射
1 请解释反射的基本原理和其实现的基石
2 .NET提供了哪些类型来实现反射
3 如何实现动态地发射程序集
4 如何利用反射来实现工厂模式

 

反射
1 请解释反射的基本原理和其实现的基石

 反射是一种动态分析程序集、模块、类型、字段等目标对象的机制,它的实现依托于元数据。元数据是存储在PE文件中的数据块,它详细记录了程序集后模块内部的结构、引用类型、程序集和清单。


2 .NET提供了哪些类型来实现反射

 在System.Reflection命名空间下,.NET提供了丰富的实现反射机制的类型,可以达到读取元数据中所有信息并且动态创建类型对象的功能。

示例:对程序集进行动态分析

首先创建一个程序集

 1 namespace NET.MST.Sixth.SimpleAssembly
 2 {
 3     /// <summary>
 4     /// 创建一个包含私有成员、特性、方法的简单类型
 5     /// </summary>
 6     [Serializable]
 7     class SimpleAssembly
 8     {
 9         private String _MyString;
10         public SimpleAssembly(String mystring)
11         {
12             _MyString = mystring;
13         }
14         public override string ToString()
15         {
16             return _MyString;
17         }
18 
19         static void Main(string[] args)
20         {
21             Console.WriteLine("简单程序集");
22             Console.Read();
23         }
24     }
25 }
View Code

 

对程序集进行分析

  1     partial class UseReflection
  2     {
  3         /// <summary>
  4         /// 对一个程序集进行分析
  5         /// </summary>
  6         /// <param name="assembly"></param>
  7         private static void AnalyzeAssembly(Assembly assembly)
  8         {
  9             Console.WriteLine("程序集名字:" + assembly.FullName);
 10             Console.WriteLine("程序集位置:" + assembly.Location);
 11             Console.WriteLine("程序集是否在GAC中:" +
 12                         assembly.GlobalAssemblyCache.ToString());
 13             Console.WriteLine("包含程序集的模块名" +
 14                 assembly.ManifestModule.Name);
 15             Console.WriteLine("运行程序集需要的CLR版本:" +
 16                 assembly.ImageRuntimeVersion);
 17             Console.WriteLine("现在开始分析程序集中的模块");
 18             Module[] modules = assembly.GetModules();
 19             foreach (Module module in modules)
 20                 AnalyzeModule(module);
 21             ////递归分析引用程序集
 22             ////这里的代码供读者参考
 23             //Console.WriteLine("开始分析引用的程序集");
 24             //AssemblyName[] refassemblies = assembly.GetReferencedAssemblies();
 25             //foreach (AssemblyName refname in refassemblies)
 26             //{
 27             //    Assembly refassembly = Assembly.Load(refname);
 28             //    AnalyzeAssembly(refassembly);
 29             //}
 30         }
 31     }
 32     partial class UseReflection
 33     {
 34         /// <summary>
 35         /// 对一个模块进行分析
 36         /// </summary>
 37         /// <param name="module">模块</param>
 38         private static void AnalyzeModule(Module module)
 39         {
 40             Console.WriteLine("模块名:" + module.Name);
 41             Console.WriteLine("模块的UUID:" + module.ModuleVersionId);
 42             Console.WriteLine("开始分析模块下的类型");
 43             Type[] types = module.GetTypes();
 44             foreach (Type type in types)
 45                 AnalyzeType(type);
 46         }
 47     }
 48     partial class UseReflection
 49     {
 50         /// <summary>
 51         /// 对一个类型进行分析
 52         /// </summary>
 53         /// <param name="type">类型</param>
 54         private static void AnalyzeType(Type type)
 55         {
 56             Console.WriteLine("类型名字:" + type.Name);
 57             Console.WriteLine("类型的类别是:" + type.Attributes);
 58             if (type.BaseType != null)
 59                 Console.WriteLine("类型的基类是:" + type.BaseType.Name);
 60             Console.WriteLine("类型的GUID是:" + type.GUID);
 61             //设置感兴趣的类型成员
 62             BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |
 63                             BindingFlags.Static | BindingFlags.Instance);
 64             //分析成员
 65             FieldInfo[] fields = type.GetFields(flags);
 66             if (fields.Length > 0)
 67             {
 68                 Console.WriteLine("开始分析类型的成员");
 69                 foreach (FieldInfo field in fields)
 70                     AnalyzeField(field);
 71             }
 72             //分析包含的方法
 73             MethodInfo[] methods = type.GetMethods(flags);
 74             if (methods.Length > 0)
 75             {
 76                 Console.WriteLine("开始分析类型的方法");
 77                 foreach (MethodInfo method in methods)
 78                     AnalyzeMethod(method);
 79             }
 80             //分析属性
 81             PropertyInfo[] properties = type.GetProperties(flags);
 82             if (properties.Length > 0)
 83             {
 84                 Console.WriteLine("开始分析类型的属性");
 85                 foreach (PropertyInfo property in properties)
 86                     AnalyzeProperty(property);
 87             }
 88         }
 89     }
 90     partial class UseReflection
 91     {
 92         /// <summary>
 93         /// 对一个成员进行分析,这里只做简单的分析
 94         /// 可以进一步分析成员的可访问级别,
 95         /// 或通过成员得到包含它的类型、模块等
 96         /// </summary>
 97         /// <param name="field">成员</param>
 98         private static void AnalyzeField(FieldInfo field)
 99         {
100             Console.WriteLine("成员名字:" + field.Name);
101             Console.WriteLine("成员的类别:" + field.Attributes);
102             Console.WriteLine("成员的类型名:" + field.FieldType.Name);
103         }
104         /// <summary>
105         /// 对一个方法进行分析
106         /// </summary>
107         /// <param name="method"></param>
108         private static void AnalyzeMethod(MethodInfo method)
109         {
110             Console.WriteLine("方法名字:" + method.Name);
111             Console.WriteLine("方法的类别:" + method.Attributes);
112             Console.WriteLine("开始分析方法的参数");
113             ParameterInfo[] parameters = method.GetParameters();
114             if (parameters.Length <= 0)
115                 Console.WriteLine("方法没有参数");
116             foreach (ParameterInfo parameter in parameters)
117                 AnalyzeParameter(parameter);
118             ParameterInfo retpar = method.ReturnParameter;
119             Console.WriteLine("分析方法的返回参数");
120             AnalyzeParameter(retpar);
121         }
122         /// <summary>
123         /// 分析方法参数
124         /// </summary>
125         /// <param name="parameter"></param>
126         private static void AnalyzeParameter(ParameterInfo parameter)
127         {
128             Console.WriteLine("参数名字:" + parameter.Name);
129             Console.WriteLine("参数的类别:" + parameter.Attributes);
130             Console.WriteLine("参数的类型:" + parameter.ParameterType.Name);
131         }
132         /// <summary>
133         /// 分析属性
134         /// </summary>
135         /// <param name="property"></param>
136         private static void AnalyzeProperty(PropertyInfo property)
137         {
138             Console.WriteLine("属性名字:" + property.Name);
139             Console.WriteLine("属性的类别:" + property.Attributes);
140             Console.WriteLine("是否可读:" + property.CanRead.ToString());
141             Console.WriteLine("是否可写:" + property.CanWrite.ToString());
142         }
143     }
View Code

 

调用:

 1     /// <summary>
 2     /// 这里的特性要求程序的运行需要完全信任的安全级别
 3     /// </summary>
 4     [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
 5     partial class UseReflection
 6     {
 7         static void Main(string[] args)
 8         {
 9             //需要根据代码位置进行更新
10             //对程序集进行遍历分析
11             Assembly assembly = Assembly.LoadFrom(@"D:\project\CSHARP\SimpleAssembly.exe");
12             AnalyzeAssembly(assembly);
13 
14             //创建一个程序集中的类型的对象
15             //这里尝试创建SimpleAssembly对象
16             Console.WriteLine("利用反射创建类型");
17             String[] pars = { "测试反射" };
18             Object o = assembly.CreateInstance(assembly.GetModules()[0].GetTypes()[0].ToString(),
19                 true, BindingFlags.CreateInstance, null, pars, null, null);
20             Console.WriteLine(o);
21             Console.Read();
22         }
23     }
View Code

 

输出:

  1 运行程序集需要的CLR版本:v4.0.30319
  2 现在开始分析程序集中的模块
  3 模块名:SimpleAssembly.exe
  4 模块的UUID:8f75ce48-76e6-40af-9f7f-adbd2fab16c6
  5 开始分析模块下的类型
  6 类型名字:SimpleAssembly
  7 类型的类别是:AutoLayout, AnsiClass, Class, Serializable, BeforeFieldInit
  8 类型的基类是:Object
  9 类型的GUID是:c0a636a7-5724-35f3-9947-4ac9ac7f9fe7
 10 开始分析类型的成员
 11 成员名字:_MyString
 12 成员的类别:Private
 13 成员的类型名:String
 14 开始分析类型的方法
 15 方法名字:ToString
 16 方法的类别:PrivateScope, Public, Virtual, HideBySig
 17 开始分析方法的参数
 18 方法没有参数
 19 分析方法的返回参数
 20 参数名字:
 21 参数的类别:None
 22 参数的类型:String
 23 方法名字:Main
 24 方法的类别:PrivateScope, Private, Static, HideBySig
 25 开始分析方法的参数
 26 参数名字:args
 27 参数的类别:None
 28 参数的类型:String[]
 29 分析方法的返回参数
 30 参数名字:
 31 参数的类别:None
 32 参数的类型:Void
 33 方法名字:Equals
 34 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
 35 开始分析方法的参数
 36 参数名字:obj
 37 参数的类别:None
 38 参数的类型:Object
 39 分析方法的返回参数
 40 参数名字:
 41 参数的类别:None
 42 参数的类型:Boolean
 43 方法名字:GetHashCode
 44 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
 45 开始分析方法的参数
 46 方法没有参数
 47 分析方法的返回参数
 48 参数名字:
 49 参数的类别:None
 50 参数的类型:Int32
 51 方法名字:GetType
 52 方法的类别:PrivateScope, Public, HideBySig
 53 开始分析方法的参数
 54 方法没有参数
 55 分析方法的返回参数
 56 参数名字:
 57 参数的类别:None
 58 参数的类型:Type
 59 方法名字:Finalize
 60 方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
 61 开始分析方法的参数
 62 方法没有参数
 63 分析方法的返回参数
 64 参数名字:
 65 参数的类别:None
 66 参数的类型:Void
 67 方法名字:MemberwiseClone
 68 方法的类别:PrivateScope, Family, HideBySig
 69 开始分析方法的参数
 70 方法没有参数
 71 分析方法的返回参数
 72 参数名字:
 73 参数的类别:None
 74 参数的类型:Object
 75 类型名字:DownloadHelper
 76 类型的类别是:AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
 77 类型的基类是:Object
 78 类型的GUID是:7c376104-a9d8-3a0b-89a2-ae567c8a86d9
 79 开始分析类型的方法
 80 方法名字:DownloadBaiduWenku
 81 方法的类别:PrivateScope, Public, Static, HideBySig
 82 开始分析方法的参数
 83 方法没有参数
 84 分析方法的返回参数
 85 参数名字:
 86 参数的类别:None
 87 参数的类型:Void
 88 方法名字:ToString
 89 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
 90 开始分析方法的参数
 91 方法没有参数
 92 分析方法的返回参数
 93 参数名字:
 94 参数的类别:None
 95 参数的类型:String
 96 方法名字:Equals
 97 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
 98 开始分析方法的参数
 99 参数名字:obj
100 参数的类别:None
101 参数的类型:Object
102 分析方法的返回参数
103 参数名字:
104 参数的类别:None
105 参数的类型:Boolean
106 方法名字:GetHashCode
107 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
108 开始分析方法的参数
109 方法没有参数
110 分析方法的返回参数
111 参数名字:
112 参数的类别:None
113 参数的类型:Int32
114 方法名字:GetType
115 方法的类别:PrivateScope, Public, HideBySig
116 开始分析方法的参数
117 方法没有参数
118 分析方法的返回参数
119 参数名字:
120 参数的类别:None
121 参数的类型:Type
122 方法名字:Finalize
123 方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
124 开始分析方法的参数
125 方法没有参数
126 分析方法的返回参数
127 参数名字:
128 参数的类别:None
129 参数的类型:Void
130 方法名字:MemberwiseClone
131 方法的类别:PrivateScope, Family, HideBySig
132 开始分析方法的参数
133 方法没有参数
134 分析方法的返回参数
135 参数名字:
136 参数的类别:None
137 参数的类型:Object
138 类型名字:RARHelper
139 类型的类别是:AutoLayout, AnsiClass, Class, BeforeFieldInit
140 类型的基类是:Object
141 类型的GUID是:d5b4c611-21be-375b-9e4b-f4d9b3a20ad8
142 开始分析类型的方法
143 方法名字:Exists
144 方法的类别:PrivateScope, Public, Static, HideBySig
145 开始分析方法的参数
146 方法没有参数
147 分析方法的返回参数
148 参数名字:
149 参数的类别:None
150 参数的类型:Boolean
151 方法名字:CompressRAR
152 方法的类别:PrivateScope, Public, HideBySig
153 开始分析方法的参数
154 参数名字:path
155 参数的类别:None
156 参数的类型:String
157 参数名字:rarPath
158 参数的类别:None
159 参数的类型:String
160 参数名字:rarName
161 参数的类别:None
162 参数的类型:String
163 分析方法的返回参数
164 参数名字:
165 参数的类别:None
166 参数的类型:Void
167 方法名字:UnRAR
168 方法的类别:PrivateScope, Public, HideBySig
169 开始分析方法的参数
170 参数名字:path
171 参数的类别:None
172 参数的类型:String
173 参数名字:rarPath
174 参数的类别:None
175 参数的类型:String
176 参数名字:rarName
177 参数的类别:None
178 参数的类型:String
179 分析方法的返回参数
180 参数名字:
181 参数的类别:None
182 参数的类型:Boolean
183 方法名字:ToString
184 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
185 开始分析方法的参数
186 方法没有参数
187 分析方法的返回参数
188 参数名字:
189 参数的类别:None
190 参数的类型:String
191 方法名字:Equals
192 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
193 开始分析方法的参数
194 参数名字:obj
195 参数的类别:None
196 参数的类型:Object
197 分析方法的返回参数
198 参数名字:
199 参数的类别:None
200 参数的类型:Boolean
201 方法名字:GetHashCode
202 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
203 开始分析方法的参数
204 方法没有参数
205 分析方法的返回参数
206 参数名字:
207 参数的类别:None
208 参数的类型:Int32
209 方法名字:GetType
210 方法的类别:PrivateScope, Public, HideBySig
211 开始分析方法的参数
212 方法没有参数
213 分析方法的返回参数
214 参数名字:
215 参数的类别:None
216 参数的类型:Type
217 方法名字:Finalize
218 方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
219 开始分析方法的参数
220 方法没有参数
221 分析方法的返回参数
222 参数名字:
223 参数的类别:None
224 参数的类型:Void
225 方法名字:MemberwiseClone
226 方法的类别:PrivateScope, Family, HideBySig
227 开始分析方法的参数
228 方法没有参数
229 分析方法的返回参数
230 参数名字:
231 参数的类别:None
232 参数的类型:Object
233 类型名字:TextHelper
234 类型的类别是:AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
235 类型的基类是:Object
236 类型的GUID是:d80fb451-1793-3d34-9986-c0216b355090
237 开始分析类型的方法
238 方法名字:GetFileEncodeType
239 方法的类别:PrivateScope, Public, Static, HideBySig
240 开始分析方法的参数
241 参数名字:filename
242 参数的类别:None
243 参数的类型:String
244 分析方法的返回参数
245 参数名字:
246 参数的类别:None
247 参数的类型:Encoding
248 方法名字:ToString
249 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
250 开始分析方法的参数
251 方法没有参数
252 分析方法的返回参数
253 参数名字:
254 参数的类别:None
255 参数的类型:String
256 方法名字:Equals
257 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
258 开始分析方法的参数
259 参数名字:obj
260 参数的类别:None
261 参数的类型:Object
262 分析方法的返回参数
263 参数名字:
264 参数的类别:None
265 参数的类型:Boolean
266 方法名字:GetHashCode
267 方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
268 开始分析方法的参数
269 方法没有参数
270 分析方法的返回参数
271 参数名字:
272 参数的类别:None
273 参数的类型:Int32
274 方法名字:GetType
275 方法的类别:PrivateScope, Public, HideBySig
276 开始分析方法的参数
277 方法没有参数
278 分析方法的返回参数
279 参数名字:
280 参数的类别:None
281 参数的类型:Type
282 方法名字:Finalize
283 方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
284 开始分析方法的参数
285 方法没有参数
286 分析方法的返回参数
287 参数名字:
288 参数的类别:None
289 参数的类型:Void
290 方法名字:MemberwiseClone
291 方法的类别:PrivateScope, Family, HideBySig
292 开始分析方法的参数
293 方法没有参数
294 分析方法的返回参数
295 参数名字:
296 参数的类别:None
297 参数的类型:Object
298 利用反射创建类型
299 测试反射
View Code

 

 


3 如何实现动态地发射程序集

 在System.Relflection.Emit命名空间下,定义一系列用于动态发射中间代码的类型,这些类型可以用来动态地创建程序集的功能。生成的中间代码被直接写入内存中,而不是以代码的形式驻留在硬盘上。

示例:动态地发射MSIL指令构成一个程序集:

  1     class MainClass
  2     {
  3         /// <summary>
  4         /// 使用发射的类型
  5         /// </summary>
  6         /// <param name="args"></param>
  7         static void Main(string[] args)
  8         {
  9             //定义构造方法的参数
 10             Object[] ctorParams = new Object[2];
 11             ctorParams[0] = 1000;
 12             ctorParams[1] = 2000;
 13             //发射程序集,并得到AddClass类型
 14             Type type = CreateAssembly();
 15             //新建AddClass对象
 16             object ptInstance = Activator.CreateInstance(type, ctorParams);
 17             //调用动态发射的ToString方法
 18             Console.WriteLine(ptInstance.ToString());
 19             //调用动态发射的GetResult方法
 20             MethodInfo info = type.GetMethod("GetResult",new Type[0]);
 21             long result = (long)info.Invoke(ptInstance, null);
 22             Console.WriteLine(result.ToString());
 23             Console.Read();
 24         }
 25 
 26         /// <summary>
 27         /// 用来动态发射一个程序集的中间代码
 28         /// 放回发射的类型
 29         /// 创建的中间代码相当于这样的C#代码:
 30         // public class AddClass
 31         //{
 32         //     private long first;
 33         //     private long second;
 34         
 35         //     public AddClass(long f, long s)
 36         //     {
 37         //         first = f;
 38         //         second = s;
 39         //     }
 40         //     public long GetResult()
 41         //     {
 42         //         return first + second;
 43         //     }
 44         
 45         //     public override string ToString()
 46         //     {
 47         //         return      "第一个数字是:" +
 48         //                     first.ToString() +
 49         //                        "\r\n第二个数字是:" +
 50         //                       second.ToString();
 51         //     }
 52         // }
 53         /// </summary>
 54         static Type CreateAssembly()
 55         {
 56             //在当前应用程序域中定义新程序集
 57             AppDomain myDomain = Thread.GetDomain();
 58             AssemblyName myAsmName = new AssemblyName();
 59             myAsmName.Name = "NewAssembly";
 60             AssemblyBuilder assemblybuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
 61             //定义模块
 62             ModuleBuilder addclassModule = assemblybuilder.DefineDynamicModule("AddClass", "AddClass.dll");
 63             //定义模块中的类型
 64             TypeBuilder addclass = addclassModule.DefineType("AddClass", TypeAttributes.Public);
 65             //这个类型将包含两个私有成员
 66             //名字分别为:first和second
 67             FieldBuilder first = addclass.DefineField("first", typeof(long), FieldAttributes.Private);
 68             FieldBuilder second = addclass.DefineField("second", typeof(long), FieldAttributes.Private);
 69             //为AddClass定义一个公共构造方法
 70             //接受两个长整型参数
 71             Type[] ctorParams = new Type[] { typeof(long), typeof(long) };
 72             //AddClass的基类是System.Object
 73             Type objType = Type.GetType("System.Object");
 74             //得到无参数构造方法
 75             ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
 76             //AddClass的公共构造方法
 77             ConstructorBuilder addCtor = addclass.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctorParams);
 78             //开始生成构造方法的中间代码
 79             ILGenerator ctorIL = addCtor.GetILGenerator();
 80             ctorIL.Emit(OpCodes.Ldarg_0);
 81             ctorIL.Emit(OpCodes.Call, objCtor);
 82             ctorIL.Emit(OpCodes.Ldarg_0);
 83             ctorIL.Emit(OpCodes.Ldarg_1);
 84             ctorIL.Emit(OpCodes.Stfld, first);
 85             ctorIL.Emit(OpCodes.Ldarg_0);
 86             ctorIL.Emit(OpCodes.Ldarg_2);
 87             ctorIL.Emit(OpCodes.Stfld, second);
 88             ctorIL.Emit(OpCodes.Ret);
 89             //这里生成long GetResult()方法
 90             //用以得到两个数字相加的结果
 91             MethodBuilder resultMethod = addclass.DefineMethod("GetResult", MethodAttributes.Public, typeof(long), new Type[0]);
 92             //发射GetResult方法的中间代码
 93             ILGenerator resultIL = resultMethod.GetILGenerator();
 94             // ILGenerator.EmitWriteLine(string) 生成一个字符串对象,
 95             //并且通过控制台输出 
 96             resultIL.EmitWriteLine("开始执行相加:");
 97             //执行相加程序
 98             //这里的IL代码用来导入两个成员变量,相加并返回结果
 99             resultIL.Emit(OpCodes.Ldarg_0);
100             resultIL.Emit(OpCodes.Ldfld, first);
101             resultIL.Emit(OpCodes.Ldarg_0);
102             resultIL.Emit(OpCodes.Ldfld, second);
103             resultIL.Emit(OpCodes.Add);
104             resultIL.Emit(OpCodes.Ret);
105             //发射String ToString方法
106             MethodBuilder tostringMethod = addclass.DefineMethod("ToString", MethodAttributes.Virtual | MethodAttributes.Public, typeof(String), new Type[0]);
107             ILGenerator stringIL = tostringMethod.GetILGenerator();
108             stringIL.Emit(OpCodes.Ldstr,"第一个数字是:");
109             stringIL.Emit(OpCodes.Ldarg_0);
110             stringIL.Emit(OpCodes.Ldflda, first);
111             stringIL.Emit(OpCodes.Call, typeof(long).GetMethod("ToString",new Type[0]));
112             stringIL.Emit(OpCodes.Ldstr, "\r\n第二个数字是:");
113             stringIL.Emit(OpCodes.Ldarg_0);
114             stringIL.Emit(OpCodes.Ldflda, second);
115             stringIL.Emit(OpCodes.Call, typeof(long).GetMethod("ToString", new Type[0]));
116             Type[] types = new Type[4];
117             for (int i = 0; i < types.Length; i++)
118                 types[i] = typeof(String);
119             stringIL.Emit(OpCodes.Call, typeof(String).GetMethod("Concat",types));
120             stringIL.Emit(OpCodes.Ret);
121             //说明方法重载System.Object方法
122             addclass.DefineMethodOverride(tostringMethod, typeof(System.Object).GetMethod("ToString"));
123             return addclass.CreateType();
124         }
125     }
View Code

 

输出:

第一个数字是:1000
第二个数字是:2000
开始执行相加:
3000


4 如何利用反射来实现工厂模式

使用反射可以实现灵活性较高的工厂模式 ,其关键在于动态地查找产品所包含的所有零件,而不需要通过代码来逐一分析使用者的需求。反射工厂模式具有灵活性高、运行效率相对较低等特点。

示例:

以打造一个房子为例,可能需要窗户、屋顶、柱子等零部件。有的屋子需要多根柱子,而有的屋子又不需要窗户。这样的需求,采用工厂模式就非常适合。

传统的工厂模式的架构图:

工厂模式传统实现:

  1     /// <summary>
  2     /// 使用者
  3     /// </summary>
  4     class Customer
  5     {
  6         static void Main(string[] args)
  7         {
  8             //根据需要获得不同的产品零件
  9             IProduct window = FactoryManager.GetProduct(RoomParts.Window);
 10             IProduct roof = FactoryManager.GetProduct(RoomParts.Roof);
 11             IProduct pillar = FactoryManager.GetProduct(RoomParts.Pillar);
 12             Console.Read();
 13         }
 14     }
 15     /// <summary>
 16     /// 屋子产品的零件
 17     /// </summary>
 18     enum RoomParts
 19     {
 20         Roof,
 21         Window,
 22         Pillar
 23     }
 24     /// <summary>
 25     /// 工厂接口
 26     /// </summary>
 27     interface IFactory
 28     {
 29         IProduct Produce();
 30     }
 31     /// <summary>
 32     /// 产品接口
 33     /// </summary>
 34     interface IProduct
 35     {
 36         String GetName();
 37     }
 38     /// <summary>
 39     /// 工厂管理者
 40     /// </summary>
 41     class FactoryManager
 42     {
 43         public static IProduct
 44             GetProduct(RoomParts part)
 45         {
 46             IFactory factory = null;
 47             //这里就是传统工厂模式的弊端
 48             //工厂管理者和工厂类族耦合
 49             switch (part)
 50             {
 51                 case RoomParts.Pillar:
 52                     factory = new PillarFactory();
 53                     break;
 54                 case RoomParts.Roof:
 55                     factory = new RoofFactory();
 56                     break;
 57                 case RoomParts.Window:
 58                     factory = new WindowFactory();
 59                     break;
 60             }
 61             IProduct product = factory.Produce();
 62             Console.WriteLine("生产了一个产品:" +
 63                     product.GetName());
 64             return product;
 65         }
 66     }
 67     #region 工厂类族
 68     class RoofFactory : IFactory
 69     {
 70         public IProduct Produce()
 71         {
 72             return new Roof();
 73         }
 74     }
 75     class WindowFactory : IFactory
 76     {
 77         public IProduct Produce()
 78         {
 79             return new Window();
 80         }
 81     }
 82     class PillarFactory : IFactory
 83     {
 84         public IProduct Produce()
 85         {
 86             return new Pillar();
 87         }
 88     }
 89     #endregion
 90 
 91     #region 产品类族
 92     class Roof : IProduct
 93     {
 94         public String GetName()
 95         {
 96             return "屋顶";
 97         }
 98     }
 99     class Window : IProduct
100     {
101         public String GetName()
102         {
103             return "窗户";
104         }
105     }
106     class Pillar : IProduct
107     {
108         public String GetName()
109         {
110             return "柱子";
111         }
112     }
113     #endregion
View Code

 

输出:

生产了一个产品:窗户
生产了一个产品:屋顶
生产了一个产品:柱子

反射工厂模式实现:

  1     /// <summary>
  2     /// 使用者
  3     /// </summary>
  4     class Customer
  5     {
  6         static void Main(string[] args)
  7         {
  8             //使用者的代码和传统实现一样
  9             IProduct window = FactoryManager.GetProduct(RoomParts.Window);
 10             IProduct pillar = FactoryManager.GetProduct(RoomParts.Pillar);
 11             IProduct roof = FactoryManager.GetProduct(RoomParts.Roof);
 12             Console.Read();
 13         }
 14     }
 15     /// <summary>
 16     /// 工厂管理类型
 17     /// </summary>
 18     class FactoryManager
 19     {
 20         public static IProduct GetProduct(RoomParts part)
 21         {
 22             Factory factory = new Factory();
 23             IProduct product = factory.Produce(part);
 24             Console.WriteLine("生产了一个产品:" +
 25                 product.GetName());
 26             return product;
 27         }
 28     }
 29 
 30     /// <summary>
 31     /// 屋子产品的零件
 32     /// </summary>
 33     enum RoomParts
 34     {
 35         Roof,
 36         Window,
 37         Pillar
 38     }
 39     /// <summary>
 40     /// 这个特性用来附加在产品类型之上,
 41     /// 来标注该类型代码哪个产品,方便反射使用
 42     /// </summary>
 43     [AttributeUsage(AttributeTargets.Class)]
 44     class ProductAttribute : Attribute
 45     {
 46         //标注零件的成员
 47         private RoomParts _myRoomPart;
 48 
 49         public ProductAttribute(RoomParts part)
 50         {
 51             _myRoomPart = part;
 52         }
 53         public RoomParts RoomPart
 54         {
 55             get 
 56             {
 57                 return _myRoomPart;
 58             }
 59         }
 60     }
 61     /// <summary>
 62     /// 这个特性用来附加在产品接口之上
 63     /// 来标注一共实现了多少产品零件,方便反射使用
 64     /// </summary>
 65     [AttributeUsage(AttributeTargets.Interface)]
 66     class ProductListAttribute : Attribute
 67     {
 68         private Type[] _myList;
 69 
 70         public ProductListAttribute(Type[] Products)
 71         {
 72             _myList = Products;
 73         }
 74         public Type[] ProductList
 75         {
 76             get
 77             {
 78                 return _myList;
 79             }
 80         }
 81     }
 82 
 83     #region 产品类族
 84     /// <summary>
 85     /// 产品零件接口,
 86     /// 需要添加所有实现该接口的列表
 87     /// </summary>
 88     [ProductList(new Type[]{
 89                 typeof(Roof),
 90                 typeof(Window),
 91                 typeof(Pillar)})]
 92     interface IProduct
 93     {
 94         String GetName();
 95     }
 96     /// <summary>
 97     /// 屋顶类型
 98     /// </summary>
 99     [Product(RoomParts.Roof)]
100     class Roof : IProduct
101     {
102         public String GetName()
103         {
104             return "屋顶";
105         }
106     }
107     /// <summary>
108     /// 窗户类型
109     /// </summary>
110     [Product(RoomParts.Window)]
111     class Window : IProduct
112     {
113         public String GetName()
114         {
115             return "窗户";
116         }
117     }
118     /// <summary>
119     /// 柱子类型
120     /// </summary>
121     [Product(RoomParts.Pillar)]
122     class Pillar : IProduct
123     {
124         public String GetName()
125         {
126             return "柱子";
127         }
128     }
129     #endregion
130 
131     #region 工厂类
132     /// <summary>
133     /// 工厂类型,这里不再需要一个类族,
134     /// 而只需要一个工厂类型
135     /// </summary>
136     class Factory
137     {
138         public IProduct Produce(RoomParts part)
139         {
140             //通过反射,从IProduct 接口中获得属性,
141             //从而获得所有的产品零件列表
142             ProductListAttribute Attr = (ProductListAttribute)
143                     Attribute.GetCustomAttribute(typeof(IProduct),
144                             typeof(ProductListAttribute));
145 
146             //遍历所有的实现产品零件类型
147             foreach (Type type in Attr.ProductList)
148             {
149                 //利用反射查找其属性
150                 ProductAttribute pa = (ProductAttribute)
151                                     Attribute.GetCustomAttribute(
152                                     type, typeof(ProductAttribute));
153                 //确定是否是需要的零件
154                 if (pa.RoomPart == part)
155                 {
156                     //再一次利用反射
157                     //创建产品零件类型
158                     Object product = Assembly.GetExecutingAssembly().
159                         CreateInstance(type.FullName);
160                     return product as IProduct;
161                 }
162             }
163             //不应该到达这里
164             return null;
165         }
166     }
167     #endregion
View Code

 

转载请注明出处:

作者:JesseLZJ
出处:http://jesselzj.cnblogs.com

posted @ 2015-09-12 00:16  JesseLZJ  阅读(419)  评论(0编辑  收藏  举报