最近我和一位同事谈论C ++,并哀叹没有办法用类字段的名字取一个字符串并用该名称提取字段;换句话说,它缺乏反思。他给了我一个莫名其妙的表情,并问任何人什么时候需要做这样的事情。
除了“嘿,我现在需要立即行动”之外,我对他没有一个好的答案。所以我坐下来想出了一些我用各种语言反射实际完成的事情。不幸的是,我的大多数例子来自我在Python中的Web编程,我希望这里的人会有更多的例子。这是我提出的清单:
给定配置文件的行如
x =“Hello World!”
y = 5.0
动态设置某些config
对象的字段等于该文件中的值。 (这是我希望我能用C ++做的,但实际上做不到。)
排序对象列表时,根据配置文件或Web请求中属性名称的任意属性进行排序。
编写使用网络协议的软件时,反射允许您根据该协议的字符串值调用方法。例如,我写了一个可以翻译的IRC机器人
!some_command arg1 arg2
进入方法调用actions.some_command(arg1, arg2)
并打印返回IRC频道的函数。
当使用Python的__getattr__函数(类似于Ruby / Smalltalk中的method_missing)时,我正在使用一个包含大量统计信息的类,例如late_total。对于每个统计数据,我希望能够添加_percent以将该统计数据作为我计算的总数的百分比(例如,stats.late_total_percent)。反思使这很容易。
所以这里的任何人都可以提供他们自己的编程经验中的任何例子,当时反思有帮助吗?下一次同事问我为什么“想做那样的事情”我想做好准备。
答案 0 :(得分:16)
我可以列出以下反射用法:
我个人经历反思的一些现实用法:
反思是好事:))
答案 1 :(得分: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;
复制/粘贴继承和代码生成更容易。
答案 2 :(得分:3)
我现在处于一种情况,即我通过网络传输XML流,我需要实例化一个Entity对象,该对象将从流中的元素填充自己。使用反射来确定哪个Entity对象可以处理哪个XML元素比编写一个巨大的维护噩梦条件语句更容易。显然,XML模式与我如何构造和命名对象之间存在依赖关系,但我控制它们,所以这不是一个大问题。
答案 3 :(得分:2)
有很多次你想要动态实例化并使用直到运行时才知道类型的对象。例如,使用OR-mappers或插件架构。如果你想编写一个日志库并动态地想要检查异常的类型和属性,模拟框架就会使用它。
如果我想再长一点,我可能会想出更多的例子。
答案 4 :(得分:2)
如果输入数据(如xml)具有易于映射到对象实例的复杂结构,或者我需要某些实例之间的“是”关系,我发现反射非常有用。
由于java中的反射相对容易,我有时会将它用于简单的数据(键值映射),其中我有一小组固定的键。一方面很容易确定一个键是否有效(如果该类有一个setter setKey(String data)),另一方面我可以改变(文本)输入数据的类型并隐藏转换(例如简单的转换) to get in getKey()),因此应用程序的其余部分可以依赖正确输入的数据。 如果一个对象的某些键值对的类型发生了变化(例如,将int形式转换为浮点数),我只需要在数据对象及其用户中更改它,但也不必记住检查解析器。如果表现是一个问题,这可能不是一个明智的方法......
答案 5 :(得分:1)
编写调度员。 Twisted使用python的反射功能来分派XML-RPC和SOAP调用。 RMI使用Java的反射api进行调度。
命令行解析。根据传入的命令行参数构建配置对象。
在编写单元测试时,使用反射会很有帮助,尽管大多数情况下我都使用它来绕过访问修饰符(Java)。
答案 6 :(得分:1)
当框架中有一些内部或私有方法或我想访问的第三方库时,我在C#中使用了反射。
(免责声明:这不一定是最佳做法,因为在以后的版本中可能会更改私有和内部方法。但它可以满足我的需要。)
答案 7 :(得分:1)
嗯,在静态类型的语言中,您需要在需要执行“动态”操作时使用反射。它可以方便地用于工具(扫描对象的成员)。在Java中,它在JMX和动态代理中使用了很多。并且有大量的一次性案例,它真的是唯一的方法(几乎任何时候你需要做一些编译器不会让你做的事情)。
答案 8 :(得分:1)
我通常使用反射进行调试。与各种各样的打印语句相比,反射可以更容易,更准确地显示系统内的对象。在许多具有一流功能的语言中,您甚至可以在不编写特殊代码的情况下调用对象的功能。
然而,有一种方法可以做你想要的(ed)。使用哈希表。存储键入字段名称的字段。
如果你真的想,你可以创建标准的Get / Set函数,或创建动态执行的宏。 #define GetX() Get("X")
有点事。
你甚至可以用这种方式实现你自己不完美的反射。
对于高级用户,如果可以编译代码,则可以启用调试输出生成并使用它来执行反射。