反射到底是什么?我读了关于这个主题的维基百科文章,我明白这是一种元编程,程序可以在运行时修改自身,但这是什么意思呢?在什么情况下这是一个好方法?什么时候最好使用它?

有帮助吗?

解决方案

反射是一种设施,其中可以查询关于其在运行时属性的对象。例如,Python,Java和.NET有设施,你可以找到一个对象的实例变量或方法。

有反射的应用的一个例子是O / R映射层。一些使用反射由quering其在运行时性能和动态填充一个实例来构造对象。这样就可以做到这一点编程基于从某种数据字典的元数据,而不必重新编译应用程序。

要举一个简单的例子,我将使用Python,因为它的反射设施使用,并且涉及除Java或.NET的样板少非常简单。

ActivePython 2.5.2.2 (ActiveState Software Inc.) based on
Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class foo:
...     def __init__(self):
...             self.x = 1
...
>>> xx = foo()      # Creates an object and runs the constructor
>>> xx.__dict__     # System metadata about the object
{'x': 1}
>>> a = xx.__dict__ # Now we manipulate the object through 
>>> a['y'] = 2      # its metadata ...
>>> print xx.y      # ... and suddenly it has a new instance variable
2                   
>>>

现在,我们已经使用了基本的反射来检查任意对象的实例变量。关于Python特殊变量__dict__是具有其成员由变量(或方法)的名称键入的哈希表的对象的系统属性。我们已经沉思检查的对象和所使用的反射设施到第二实例变量人工捅到它,这是我们可以然后通过调用它作为一个实例变量显示。

请注意,这个特殊的伎俩不会对Java或.NET工作,因为实例变量是固定的。这些语言的类型系统不允许在运行时在Python的“鸭子”类型系统的方式做可以增加新的实例变量。但是,你可能会反射性地更新,这是在类型定义中声明的实例变量的值。

您也可以使用反射动态构建方法调用和执行各种其他整齐花样如实例基于参数的对象。例如,如果你有某种形式的基于插件系统,其中的某些功能是可选的,你可以使用反射(或许通过查询特定的接口是否实施),而无需显式元数据查询什么IT服务所提供的插件。

许多动态语言接口,例如OLE自动化使用反射作为接口的一个组成部分。

其他提示

没那么多 修改 代码在执行时,但检查对象并要求它们执行代码而不知道它们的静态类型。

描述它的一种简单方法是“使静态类型语言动态运行的一种有点痛苦的方法”。

编辑:用途:

  • 配置(例如获取指定类型和属性的 XML 文件,然后构造适当的对象)
  • 测试(通过名称或属性标识的单元测试)
  • Web 服务(至少在 .NET 中,核心 Web 服务引擎中使用了大量反射)
  • 自动事件连接 - 提供具有适当名称的方法,例如 SubmitButton_Click 并且 ASP.NET 会将该方法附加为处理程序 SubmitButtonClick 事件(如果您打开了自动装配)

这是不是一个好主意?好吧,只有当其他选择令人痛苦时。我更喜欢静态类型,因为它不会妨碍 - 这样你就可以获得很多编译时的好处,而且速度也更快。但是当你 需要它,反思可以让你做各种各样的事情,否则这些事情是不可能的。

第一个很好的例子,我能想到的把我的头顶部是当你需要执行一组给定对象的方法不知道在编译时究竟会在它存在的方法。

取单元测试框架例如。测试运行器类,负责运行所有的单元测试不提前知道什么时候你要命名方法。它只知道的是,他们将与“测试”作为前缀(或Java 5的情况下,@Test注释)。所以给出一个测试类时,它反映了该类为了得到的这一切的方法的列表。然后,通过这些方法的名称作为字符串进行迭代,并调用该对象的那些方法,如果他们开始用“测试”。无反射这是不可能的。而这只是一个例子。

反射已经在至少1项目,我能想到的一直对我非常有用。写我们的内部“进程管理器”的程序,以一定的间隔进行了大量关键业务流程。该项目设置,使核心实际上就是与火了每30秒左右,并为您的工作要做计时器对象Windows服务。

在实际工作是在一个类库(适当称为“WorkerLib”)被完成的。我们定义与执行某些任务(移动文件,将数据上传到远程站点,等等)的想法是,核心服务可以调用从工人库方法,无需了解它调用了什么方法public方法的类。这让我们在数据库中的工作创造一个时间表,甚至添加新的方法到类库而不必改变核心系统。

在基本的想法是,我们可以使用反射核心服务来执行他们的名字我们已经存储在数据库中定义的时间表方法。这是在实践中相当整洁。我们的核心服务是固体并处理执行工作需要,而实际工作者库可以在没有核心进行扩展,并根据需要改变,甚至有爱心。

如果您需要进一步的解释,请随时提出。这只不过是我能想到的解释现实世界的场景,反映真正使事情变得更容易为我们的最佳方式。

又如:我有使用,需要一个数据库的输出代码 - 这是一组与已命名的列行的 - 它馈入对象的数组。我通过迭代行,如果目标对象具有相同的名称和类型的属性,我将它设置。这使我的数据获取的代码只是看起来像这样:

SqlDataReader sdr = Helper.GetReader("GetClientByID", ClientID);
Client c = new Client();
FillObject(sdr, c);
return c;

真的,反射应该被看作是排序的代码放大器。它可以使优秀的代码更好,更洁净,和糟糕的代码变得更糟。它有什么作用?它真的可以让你写的代码,你不能完全肯定什么它会在你写它的时候做。你有一个总体思路,但它可以让你不代码什么对象,方法和属性会在程序编译时执行。

其他职位是正确的,当他们说,它允许程序来执行基于配置值的代码,但它真正的力量在于,它可以让你严重弯曲的面向对象编程的规则。这真的是它做什么。这是一种像旋转的安全措施了。私有方法和属性可以通过反射与其它任何东西一起被访问。

当MS使用反射的一个很好的例子是与数据对象上的数据绑定。您指定的文本字段和数据字段的名称为对象绑定到一个下拉列表等,并且代码反映了对象,并拿出相应的信息。数据绑定对象做一遍又一遍同样的过程了,但它不知道它有什么类型的对象将绑定。反射是编写的代码一点点地处理所有的可能情况的一个方便的方法。

在爪哇它基本上是实例化一个类,而不知道关于它的前手的方法。假设你希望用户能够通过添加他们想要你的程序中使用的类来更改配置文件(说你有一些接口的众多实现)。随着反射,你可以创建基于只需将它的名字,方法签名等的对象。 。然后将其投射到您的接口。

反射为运行时配置是有用的,允许系统的部件通过外部配置来驱动。

例如,类工厂可以构建基于输入文件,其中,所述具体类型需要不同的配置信息,以调用一个具体构造,而不是使用一个构建器接口不同的具体类型。 (该对象的构造方法被定位使用反射)。

反射是(基本上)中的程序的,以查询,这是提供给编译器类型信息的能力。因此,例如,给定一个类型,你可以查询它包含的方法的名称。然后,对于每个方法可以查询他们采取等参数类型的等等等等。

这对运行时配置,你就有了指定你的应用程序的行为的配置文件非常有用。该配置可以包含具体的类型,你应该使用的名称(如经常与IOC容器的情况下)。使用反射可以创建这个具体类型(通过反射API)的一个实例,并使用它。

我给你举个例子。

作为一种编程练习,我写了一个mp3文件检查器。它扫描我的音乐库,并显示ID1 / ID2标签我很感兴趣,在一个DataGridView。我使用反射来从MP3信息类的属性,而无需知道有关这个类的任何UI代码。如果我想改变被显示的信息我可以编辑MP3信息类或更改其配置(这取决于我如何写的类),并没有更新UI。

这也意味着我已经能够使用依赖注入使用相同的端来显示数字照片上的信息只是通过交换数据库类。

程序集包含模块,模块包含类型,类型包含成员。反射提供封装程序集、模块和类型的对象。您可以使用反射动态创建类型的实例、将该类型绑定到现有对象或从现有对象获取类型。然后,您可以调用该类型的方法或访问其字段和属性。反射的典型用途包括:

  • 使用 Assembly 定义和加载程序集、加载程序集清单中列出的模块,以及从此程序集中查找类型并创建它的实例。
  • 使用 Module 来发现信息,例如包含模块的程序集和模块中的类。您还可以获取模块上定义的所有全局方法或其他特定的非全局方法。
  • 使用 ConstructorInfo 可以发现构造函数的名称、参数、访问修饰符(例如 public 或 private)和实现细节(例如 Abstract 或 virtual)等信息。使用 Type 的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。
  • 使用 MethodInfo 可以发现方法的名称、返回类型、参数、访问修饰符(例如公共或私有)和实现细节(例如抽象或虚拟)等信息。使用类型的 GetMethods 或 GetMethod 方法来调用特定方法。
  • 使用 FieldInfo 可以发现字段的名称、访问修饰符(例如 public 或 private)和实现详细信息(例如 static)等信息,并获取或设置字段值。
  • 使用 EventInfo 可以发现事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等信息,并添加或删除事件处理程序。
  • 使用 PropertyInfo 可以发现属性的名称、数据类型、声明类型、反射类型以及只读或可写状态等信息,并获取或设置属性值。
  • 使用 ParameterInfo 可以发现参数的名称、数据类型、参数是输入参数还是输出参数以及参数在方法签名中的位置等信息。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top