24

最近我在和一位同事谈论 C++,并感叹没有办法获取具有类字段名称的字符串并提取具有该名称的字段;换句话说,它缺乏反思。他困惑地看了我一眼,问我什么时候需要做这样的事情。

在我的脑海中,我没有给他一个好的答案,除了“嘿,我现在需要做”。所以我坐下来列出了一些我实际上用各种语言反射完成的事情。不幸的是,我的大部分示例都来自我使用 Python 进行的 Web 编程,我希望这里的人们能有更多示例。这是我想出的清单:

  1. 给定一个配置文件,其中包含
    x = "Hello World!"这样的行
    y = 5.0
    动态设置某个config对象的字段等于该文件中的值。(这是我希望我能在 C++ 中做的,但实际上做不到。)

  2. 对对象列表进行排序时,根据配置文件或 Web 请求中给定属性名称的任意属性进行排序。

  3. 在编写使用网络协议的软件时,反射允许您根据来自该协议的字符串值调用方法。例如,我编写了一个 IRC 机器人,它将转换
    !some_command arg1 arg2
    为方法调用actions.some_command(arg1, arg2)并打印该函数返回给 IRC 通道的任何内容。

  4. 当使用 Python 的 __getattr__ 函数(有点像 Ruby/Smalltalk 中的 method_missing)时,我正在使用一个包含大量统计信息的类,例如 late_total。对于每个统计数据,我希望能够添加 _percent 以将该统计数据作为我计算的总事物的百分比(例如,stats.late_total_percent)。反射使这变得非常容易。

那么,这里的任何人都可以从他们自己的编程经验中举出任何例子,当时反射很有帮助吗?下一次同事问我为什么“曾经想做那样的事情”时,我想做好更多的准备。

4

9 回答 9

21

我可以列出以下反射用法:

  • 后期装订
  • 安全性(出于安全原因自省代码)
  • 代码分析
  • 动态打字(没有反射就不可能进行鸭子打字)
  • 元编程

根据我的个人经验,一些现实世界的反射用法:

  • 基于反射的插件系统开发
  • 使用面向方面的编程模型
  • 执行静态代码分析
  • 使用了各种依赖注入框架
  • ...

反思是件好事:)

于 2008-09-08T14:08:02.733 回答
4

我使用反射来获取异常、日志记录等的当前方法信息。

string src = MethodInfo.GetCurrentMethod().ToString();
string msg = "Big Mistake";
Exception newEx = new Exception(msg, ex);
newEx.Source = src;

代替

string src = "MyMethod";
string msg = "Big MistakeA";
Exception newEx = new Exception(msg, ex);
newEx.Source = src;

复制/粘贴继承和代码生成更容易。

于 2008-09-08T14:01:04.763 回答
3

我现在的情况是,我有一个通过网络传入的 XML 流,我需要实例化一个 Entity 对象,该对象将从流中的元素填充自身。使用反射来确定哪个实体对象可以处理哪个 XML 元素比编写一个庞大的、维护噩梦的条件语句更容易。XML 模式与我如何构建和命名我的对象之间显然存在依赖关系,但我控制了这两者,所以这不是一个大问题。

于 2008-09-08T14:06:31.567 回答
2

很多时候,您希望动态实例化并使用直到运行时才知道类型的对象。例如使用 OR-mappers 或插件架构。如果您想编写日志库并动态地检查异常的类型和属性,则模拟框架会使用它。

如果我想得久一点,我可能会想出更多的例子。

于 2008-09-08T13:52:27.560 回答
2

如果输入数据(如 xml)具有很容易映射到对象实例的复杂结构,或者我需要实例之间的某种“是”关系,我发现反射非常有用。

由于反射在 java 中相对容易,我有时将它用于简单的数据(键值映射),其中我有一组固定的键。一方面很容易确定一个键是否有效(如果该类有一个设置器 setKey(String data)),另一方面我可以更改(文本)输入数据的类型并隐藏转换(例如简单转换到 getKey()) 中的 int,因此应用程序的其余部分可以依赖正确键入的数据。如果某个对象的某些键值对的类型发生变化(例如,将 int 形式更改为浮动),我只需在数据对象及其用户中更改它,但不必记住也要检查解析器. 如果性能是一个问题,这可能不是一个明智的方法......

于 2008-09-08T14:46:53.967 回答
1

编写调度程序。Twisted 使用 python 的反射功能来调度 XML-RPC 和 SOAP 调用。RMI 使用 Java 的反射 API 进行调度。

命令行解析。根据传入的命令行参数构建配置对象。

在编写单元测试时,使用反射会很有帮助,尽管我主要使用它来绕过访问修饰符(Java)。

于 2008-09-08T13:52:58.683 回答
1

当我想要访问的框架或第三方库中有一些内部或私有方法时,我在 C# 中使用了反射。

(免责声明:这不一定是最佳实践,因为私有和内部方法可能会在以后的版本中更改。但它可以满足我的需要。)

于 2008-09-08T13:55:13.933 回答
1

好吧,在静态类型的语言中,任何时候你需要做一些“动态”的事情,你都想使用反射。它可用于工具目的(扫描对象的成员)。在 Java 中,它大量用于 JMX 和动态代理。并且有很多一次性的情况,它确实是唯一的方法(几乎任何时候你需要做一些编译器不允许你做的事情)。

于 2008-09-08T13:55:31.563 回答
1

我通常使用反射进行调试。与各种打印语句相比,反射可以更轻松、更准确地显示系统内的对象。在许多具有一流函数的语言中,您甚至可以调用对象的函数而无需编写特殊代码。

但是,有一种方法可以做您想做的事情(ed)。使用哈希表。存储针对字段名称键入的字段。

如果您真的想要,您可以创建标准的 Get/Set 函数,或创建动态执行此操作的宏。#define GetX() Get("X")那类的东西。

你甚至可以通过这种方式实现你自己的不完美反射。

对于高级用户,如果您可以编译代码,则可以启用调试输出生成并使用它来执行反射。

于 2008-09-21T01:18:28.317 回答