.NET基础 (17)反射
反射
1 请解释反射的基本原理和其实现的基石
2 .NET提供了哪些类型来实现反射
3 如何实现动态地发射程序集
4 如何利用反射来实现工厂模式
反射是一种动态分析程序集、模块、类型、字段等目标对象的机制,它的实现依托于元数据。元数据是存储在PE文件中的数据块,它详细记录了程序集后模块内部的结构、引用类型、程序集和清单。
在System.Reflection命名空间下,.NET提供了丰富的实现反射机制的类型,可以达到读取元数据中所有信息并且动态创建类型对象的功能。
示例:对程序集进行动态分析
首先创建一个程序集
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
对程序集进行分析
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
调用:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 测试反射
在System.Relflection.Emit命名空间下,定义一系列用于动态发射中间代码的类型,这些类型可以用来动态地创建程序集的功能。生成的中间代码被直接写入内存中,而不是以代码的形式驻留在硬盘上。
示例:动态地发射MSIL指令构成一个程序集:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
输出:
第一个数字是:1000
第二个数字是:2000
开始执行相加:
3000
使用反射可以实现灵活性较高的工厂模式 ,其关键在于动态地查找产品所包含的所有零件,而不需要通过代码来逐一分析使用者的需求。反射工厂模式具有灵活性高、运行效率相对较低等特点。
示例:
以打造一个房子为例,可能需要窗户、屋顶、柱子等零部件。有的屋子需要多根柱子,而有的屋子又不需要窗户。这样的需求,采用工厂模式就非常适合。
传统的工厂模式的架构图:
工厂模式传统实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
输出:
生产了一个产品:窗户
生产了一个产品:屋顶
生产了一个产品:柱子
反射工厂模式实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
转载请注明出处: