• .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:projectCSHARPSimpleAssembly.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         //                        "
    第二个数字是:" +
     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, "
    第二个数字是:");
    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

  • 相关阅读:
    Gitlab 进首页报错500 Whoops。 访问仓库错误码503
    iptables设置Linux全局代理
    元素到底部位置判断
    行为型设计模式:职责链模式
    Win7SP1安装.net 4.6 4.7 4.8
    深入理解并行编程 电子书 pdf
    CUDA C编程权威指南 第二版 电子书 pdf
    程序员修炼之道 第二版 电子书 pdf
    linux多线程服务端编程 电子书 pdf
    Clean Craftsmanship: Disciplines, Standards, and Ethics 电子书 pdf
  • 原文地址:https://www.cnblogs.com/jesselzj/p/4801633.html
Copyright © 2020-2023  润新知