zoukankan      html  css  js  c++  java
  • 反射定义、应用及性能

    反射概述

    反射定义

    在正式开始讲述反射之前,还是让我们先来看一下微软自己是怎么定义反射的,根据MSDN的解释:反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。说到底,反射就是一种在程序的执行期通过对程序集的类型元数据的使用动态获取其模块,类型,方法等信息的机制。

    为何需要反射

              任何一种技术的产生都有其特定的背景和使用需求,同样,反射也不例外,具体来说,我们将在下面的场景中使用到反射技术。

    ·         查看元数据,这给我们窥探程序集的内部机理提供了一种方便,很多工具也是基于此而开发的,例如ILDASMReflector

    ·         类型查看,它允许我们检查程序集中的类型并与之交互,这给我们在创建定制脚本方面提供了极大的帮助;

    ·         后期绑定,该技术通常用于解释型语言,例如脚本语言,因为其程序集中的某些类在编译期间是未知的;

    ·         运行时动态创建类型。

    反射应用

    查看元数据

                    在这里我想举一个查看自定义属性的例子(关于属性的更多内容,请参考我的另一篇文章),为此,我们得先准备一个自定义属性

    代码
     1 using System;
     2 using System.Reflection;
     3 
     4 namespace ViewCustomProperty
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             MemberInfo memberInfo = typeof(ClassWithCustomProperty);
    11             object[] customAttributes = memberInfo.GetCustomAttributes(typeof(BugFixAttribute), false);
    12             foreach (object obj in customAttributes)
    13             {
    14                 BugFixAttribute bugFixAttribute = obj as BugFixAttribute;
    15                 if (bugFixAttribute != null)
    16                 {
    17                     Console.WriteLine("BugID: {0}", bugFixAttribute.BugID);
    18                     Console.WriteLine("Programmer: {0}", bugFixAttribute.Programmer);
    19                     Console.WriteLine("Date: {0}", bugFixAttribute.Date);
    20                     Console.WriteLine("Comment: {0}\n", bugFixAttribute.Comment);
    21                 }
    22             }
    23             Console.ReadKey();
    24         }
    25     }
    26 
    27     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
    28     public class BugFixAttribute : System.Attribute
    29     {
    30         public BugFixAttribute(int bugID, string programmer, string date)
    31         {
    32             this.bugID = bugID;
    33             this.programmer = programmer;
    34             this.date = date;
    35         }
    36 
    37         public int BugID
    38         {
    39             get
    40             {
    41                 return bugID;
    42             }
    43         }
    44 
    45         public string Comment
    46         {
    47             get
    48             {
    49                 return comment;
    50             }
    51             set
    52             {
    53                 comment = value;
    54             }
    55         }
    56 
    57         public string Date
    58         {
    59             get
    60             {
    61                 return date;
    62             }
    63         }
    64 
    65         public string Programmer
    66         {
    67             get
    68             {
    69                 return programmer;
    70             }
    71         }
    72 
    73         private int bugID;
    74         private string comment;
    75         private string date;
    76         private string programmer;
    77     }
    78  
    79     [BugFixAttribute(66180"Chunting Pan""01/01/2010")]
    80     [BugFixAttribute(66181"Chunting Pan""12/31/2010", Comment = "Rollback the changes from previous version")]
    81     public class ClassWithCustomProperty
    82     {
    83         public void Display()
    84 
    85         {
    86             Console.WriteLine("This is a class with custom property");
    87         }
    88     }
    89 }

     运行的结果如下:

    BugID: 66180

    Programmer: Chunting Pan

    Date: 01/01/2010

    Comment:

     

    BugID: 66181

    Programmer: Chunting Pan

    Date: 12/31/2010

    Comment: Rollback the changes from previous version

    类型查看

    类型查看非常简单,在此不想浪费太多时间,让我们直接看一个例子,此例子返回正在运行的程序集的所有类型信息。

    代码
     1 using System;
     2 using System.Reflection;
     3 
     4 namespace TypeDiscovery
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Assembly assembly = Assembly.GetExecutingAssembly();
    11             Type[] types = assembly.GetTypes();
    12             foreach (Type type in types)
    13             {
    14                 Console.WriteLine(type);
    15             }
    16             Console.ReadKey();
    17         }
    18     }
    19 }

    运行结果如下:

    TypeDiscovery.Program

    后期绑定

             程序集A的代码可以实例化并使用一个定义在程序集B中的类型,而该类型可能在A编译的时候并没有被引用,我们把这种类型的联系描述为后期绑定。如果我们深入研究后期绑定,你将会发现这是一种很酷的技术,但限于篇幅的原因,在此不再赘述,仅以下面的例子作为参考,有兴趣的同学可以去研究一下动态语言如PythonRuby以及插件技术(Plugin)

    代码
     1 using System;
     2 using System.Reflection;
     3 
     4 namespace LateBinding
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Assembly assembly = Assembly.GetExecutingAssembly();
    11             Type type = assembly.GetType("LateBinding.Employee");
    12             Object obj = Activator.CreateInstance(type);
    13 
    14             Type[] paramTypes = new Type[1];
    15             paramTypes[0= Type.GetType("System.String");
    16             MethodInfo SayHelloMethodInfo = type.GetMethod("SayHello", paramTypes);
    17  
    18             Object[] parameters = new Object[1];
    19             parameters[0= "panchunting";
    20             Object returnVal = SayHelloMethodInfo.Invoke(obj, parameters);
    21             Console.WriteLine(returnVal);
    22             Console.ReadKey();
    23         }
    24     }
    25 
    26     public class Employee
    27     {
    28         public void SayHello(string employeeName)
    29         {
    30             Console.WriteLine("Hello, {0}", employeeName);
    31         }
    32     }
    33 }

    运行结果如下:

    Hello, panchunting

    运行时动态创建类型

                    在创建类型之前,我们得有相应的程序集,你可选择创建一个新程序集,也可以选择使用当前的程序集,下面我们分别加以说明。

    方式一:引用外部程序集

                    一般而言,程序集由DLLEXE文件组成,当然也可以包含资源文件,如JPG等,我们假定这里的程序集只包含单个DLL文件,为此我们先创建一个类库项目

    代码
     1 using System;
     2 
     3 namespace ReflectionClassLibrary
     4 {
     5     public class Employee
     6     {
     7         public Employee(string employeeName)
     8         {
     9             this.employeeName = employeeName;
    10         }
    11  
    12         private string employeeName;
    13  
    14         public void SayHello()
    15         {
    16             Console.WriteLine("Hello, " + this.employeeName);
    17         }
    18     }
    19 }

     下面创建一个控制台应用程序用于反射此程序集(当然你得先添加对此程序集的引用)

    代码
     1 using System;
     2 using System.Reflection;
     3 using ReflectionClassLibrary;
     4 
     5 namespace ReflectionEmployee
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             Assembly assembly = Assembly.LoadFrom("ReflectionClassLibrary.dll");
    12             Type type = assembly.GetType("ReflectionClassLibrary.Employee");
    13             Employee employee = Activator.CreateInstance(type, "panchunting"as Employee;
    14             if (employee != null)
    15             {
    16                 employee.SayHello();
    17             }
    18             Console.ReadKey();
    19         }
    20     }
    21 }
    22 

     运行结果如下:

    Hello, panchunting

    方式二,反射的类与反射方法在同一个程序集中

    代码
     1 using System;
     2 using System.Reflection;
     3 
     4 namespace ReflectionAllInOneAssembly
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             Assembly assembly = Assembly.GetExecutingAssembly();
    11             Type type = assembly.GetType("ReflectionAllInOneAssembly.Employee");
    12             Employee employee = Activator.CreateInstance(type, "panchunting"as Employee;
    13             if (employee != null)
    14             {
    15                 employee.SayHello();
    16             }
    17             Console.ReadKey();
    18         }
    19     }
    20 
    21     public class Employee
    22     {
    23         public Employee(string employeeName)
    24         {
    25             this.employeeName = employeeName;
    26         }
    27  
    28         private string employeeName;
    29  
    30         public void SayHello()
    31         {
    32             Console.WriteLine("Hello, " + this.employeeName);
    33         }
    34     }
    35 }
     反射与抽象工厂

           先介绍点业务逻辑知识:Performance有两种类型:PlanReview,而它们又都有三种类型的Program,即:CompetencyJobResponsibilityTrainingDevelopment

    创建抽象工厂代码如下:

     

    代码
     1 using System;
     2 using System.Text;
     3 using System.Reflection;
     4 
     5 namespace ReflectionAbstractFactory
     6 {
     7     public abstract class AbstractFactory
     8     {
     9         public abstract IProgramType CreateProgram(string ProgramTypeName);
    10     }
    11 
    12     public class ReviewProgram : AbstractFactory
    13     {
    14         public override IProgramType CreateProgram(string ProgramTypeName)
    15         {
    16             IProgramType ProgramType = null;
    17             Type type = Type.GetType("ReflectionAbstractFactory." + ProgramTypeName);
    18             if (type != null)
    19             {
    20                 ProgramType = Activator.CreateInstance(type) as IProgramType;
    21             }
    22             return ProgramType;
    23         }
    24     }
    25 
    26     public class PlanProgram : AbstractFactory
    27     {
    28         public override IProgramType CreateProgram(string ProgramTypeName)
    29         {
    30             IProgramType ProgramType = null;
    31             Type type = Type.GetType("ReflectionAbstractFactory." + ProgramTypeName);
    32             if (type != null)
    33             {
    34                 ProgramType = Activator.CreateInstance(type) as IProgramType;
    35             }
    36             return ProgramType;
    37         }
    38     }
    39 
    40     public interface IProgramType
    41     {
    42         void Display();
    43     }
    44 
    45     public class ReviewCompetency : IProgramType
    46     {
    47         public void Display()
    48         {
    49             Console.WriteLine("This is competency program of review");
    50         }
    51     }
    52 
    53     public class ReviewJobResponsibility : IProgramType
    54     {
    55         public void Display()
    56         {
    57             Console.WriteLine("This is job responsibility program of review");
    58         }
    59     }
    60 
    61     public class ReviewTrainingDevelopment : IProgramType
    62     {
    63         public void Display()
    64         {
    65             Console.WriteLine("This is training development program of review");
    66         }
    67     }
    68 
    69     public class PlanCompetency : IProgramType
    70     {
    71         public void Display()
    72         {
    73             Console.WriteLine("This is competency program of plan");
    74         }
    75     }
    76 
    77     public class PlanJobResponsibility : IProgramType
    78     {
    79         public void Display()
    80         {
    81             Console.WriteLine("This is job responsibility program of plan");
    82         }
    83     }
    84  
    85     public class PlanTrainingDevelopment : IProgramType
    86     {
    87         public void Display()
    88         {
    89             Console.WriteLine("This is training development program of plan");
    90         }
    91     }
    92 }

    控制台运行结果如下:

    Please input the class name, like ReviewCompetency:ReviewCompetency

    ------------------------------------------------------

    This is competency program of review

    ------------------------------------------------------

    Plese input any key to exit

    性能

    (MSDN)反射的性能损失主要来源于比较类型、遍历成员、调用成员三种情形,其中比较类型耗时最小,调用成员耗时最多,所以尽量减少采用成员动态调用等反射方式可以提高应用程序性能。除此之外,采取后期绑定、避免将反射方法放到循环内产生放大效应等办法均可提升反射性能。

    参考及引用

    http://msdn.microsoft.com/zh-cn/library/ms173183(VS.80).aspx

    http://msdn.microsoft.com/en-us/magazine/cc164170.aspx

    http://oreilly.com/catalog/progcsharp/chapter/ch18.html

    http://www.codeproject.com/KB/architecture/CSharpClassFactory.aspx

    http://p2p.wrox.com/content/blogs/lee-dumond/refactoring-c-aspnet-%E2%80%93-abstract-factory-reflection

    Practical .NET2 and C#2 (Harness the Platform, the Language, the Framework)

  • 相关阅读:
    [BZOJ 2457] 双端队列 (思维)
    字符串划分 [Bitset 字符串Dp]
    POJ2947 Widget Factory [高斯消元]
    数字串 [分治+哈希+扩展KMP]
    POJ3590 The shuffle Problem [置换+dp]
    P1970 花匠 [权值线段树优化dp, NOIp2003, Y]
    UVA306 Cipher[循环节]
    POJ3270 Cow Sorting [置换]
    POJ 3128 Leonardo's Notebook[置换群幂相关]
    VMware 11 设置U盘启动,总是找不到physicalDrive1
  • 原文地址:https://www.cnblogs.com/panchunting/p/CSharpReflection.html
Copyright © 2011-2022 走看看