多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
Haxe 支持运行时的类型和字段反射。必须注意,因为运行时表示不同目标平台之间的一般差异。为了正确的使用反射,需要理解哪种类别的操作是被支持的,哪些不是。鉴于反射的动态特性,这不能总是被在编译时确定。 反射API由两个类组成: * Reflect : 一个轻量级的API,很好的使用于匿名结构,但是对类的有限支持。 * Type : 适用于类和枚举的更加健壮的API 。 可用的方法在 Reflect 和 Type API中详细介绍。 Reflection 是一个强大的工具,但是重要的是,理解它为什么也可能引起问题。举个例子,一些函数接受一个 String 参数,并试图解析它为一个类型或者字段。这很容易带来类型错误: ~~~ class Main { static function main() { trace(Type.resolveClass("Mian")); // null } } ~~~ 然而,即使没有类型错误,也很容易遇到意料之外的行为: ~~~ class Main { static function main() { // null trace(Type.resolveClass("haxe.Template")); } } ~~~ 这里的问题是,编译器从来没有真正的"看到“ haxe.Template 类型,所以它不会编译输出。此外,即使它看到过这个类型,仍然可能从有问题发生,在无用代码消除(第8.2节)消除的仅通过反射使用的类型或字段。 另一组问题来自于一个事实,一些反射函数有意的接受 Dyanmic(第2.7节) 类型的参数,也就是说,编译器不能检查在参数中传递的是不是正确的。如下的例子演示了当使用 callMethod 时一个常见的错误: ~~~ class Main { static function main() { // wrong //Reflect.callMethod(Main, "f", []); // right Reflect.callMethod(Main, Reflect.field(Main, "f"), []); } static function f() { trace('Called'); } } ~~~ 注释掉的调用可以被编译器接受,因为它分配字符串 “f” 到被指定为 Dynamic 类型的函数参数 func 。 当使用反射时一个好的建议是,包装它到被原本类型安全的代码调用的一个应用或者API的一些函数中。看一下这个例子: ~~~ typedef MyStructure = { name: String, score: Int } class Main { static function main() { var data = reflective(); // At this point data is nicely typed as MyStructure } static function reflective():MyStructure { // Work with reflection here to get some values we want to return. return { name: "Reflection", score: 0 } } } ~~~ 尽管方法 reflective 能和反射一起使用(对于这个事件,而且是Dynamic),但它返回值是一个类型化的结构,可以使调用者使用类型安全的方式。