ActionScript 3中的类反射

ActionScript 3中的类反射

什么是反射
反射 (Reflection) 是指在程序在运行时 (run-time) 获取类信息的方式. 诸如实现动态创建类实例, 方法等. 在很语言中都有相关的的实现, 如 Java 和 c# 等

反射有什么用
在 as3 与 as2 不同, 类实例中任何元素, 如变量 (variable), 访问器 (accessor, 即 getter / setter), 方法 (method) 都是不可被 for..in 遍历的 (不是默认哦, 目前我还没找到办法可以让他被遍历),
并且不管你是否继承自 Object (默认继承就是 Object, 不写也一样), 是否把类声明为 dynamic.
或许有人会问自然是 Object 的子类, 不是可以用 setPropertyIsEnumerable 来设置是否隐藏变量么.
很遗憾的是经过的我的尝试, 在类里使用 setPropertyIsEnumerable("属性名") 编译器报告方法可能未定义.
随后尝试 super.setPropertyIsEnumerable("属性名"), 编译通过但抛运行时错误, 同样是方法未定义 -_-
而其他方法诸如 propertyIsEnumerable("属性名") 却可以正常使用

新建一个 ActionScript 项目, 分别创建下面 2 个类:

Dummy.as


package
{
    
public dynamic class Dummy extends Object
    
{        
        
public var variable1:String;
        
public function Dummy () {
            variable1 
= "我是字符串";
            
            
// 使用下面 2 个句子分别会报告编译时错误和运行时错误
            
// setPropertyIsEnumerable("variable1");
            
// super.setPropertyIsEnumerable("accessorOfVar1");
        }

    
        
public function get accessorOfVar1 ():String {
            
return "通过访问器访问, variable1 : " + variable1;
        }

        
    }

}

ReflectionSample.as


package {
    
import flash.display.Sprite;


    
public class ReflectionSample extends Sprite
    
{
        
public function ReflectionSample () {
            testPropsEnumeration();
        }
                   
        
/**
         * 测试 for..in 遍历
         * 
         
*/

        
private function testPropsEnumeration ():void {
            trace(
"测试 for..in 循环, 遍历 Dummy 的实例");
            var dummy:Dummy 
= new Dummy();
            
            
for (var i:String in dummy)
                trace( i 
+ " : " + dummy[i] );
        }

    }

}

最后测试 ReflectionSample, 记得用 debug 模式. 控制台中只会出现:

QUOTE:
------------------------------------------------------------
测试 for..in 循环, 遍历 Dummy 的实例
------------------------------------------------------------

显然 dummy 中的元素都没有被遍历出.

在 as1, 2 中很简单就可以实现的问题在 as3 得换个办法了, 谁让他们是传统的脚本语言呢.而在 as3 中, 就得通过反射来解决这个问题了. 方法会在文后介绍

动态创建实例

* 这部分内容帮助中已经有例子, 我摘要一些翻译一下, 不过我的 e 文很烂. 希望大家能看得懂.

as3 使用 flash.util.getDefinitionByName 动态获取类 (Class) 引用
帮助中该方法的描述 :

QUOTE:
------------------------------------------------------------
public function getDefinitionByName(name:String):Object
返回参数 name 中指定的类引用

参数  name:String - 类名称 
返回  Object - 返回参数 name 中指定的类引用
错误  ReferenceError - 找不到参数 name 对应的公共定义
------------------------------------------------------------

使用方法如下:

获取类 flash.text.TextField 的引用. as 语句是无异常的类型转换. 如果转换失败那么目标变量将被设置成 null

var ClassReference:Class = getDefinitionByName("flash.text.TextField") as Class;

实例化所引用的类, 并设置一些属性

var instance:TextField = new ClassReference() as TextField;
instance.autoSize = "left";
instance.text = "我通过 getDefinitionByName 动态创建";

最后添加到场景中并显示

addChild(instance);

修改后的 ReflectionSample.as:


package   {
    
import flash.display.Sprite;
    
import flash.utils.getDefinitionByName;
    
import flash.text.TextField;

    
public class ReflectionSample extends Sprite
    
{
        
public function ReflectionSample () {
            getDefinitionByNameSample();
        }

        
        
/**
         * 使用 flash.utils.getDefinitionByName 动态获取类 (Class) 并创建实例
         * 
         
*/

        
private function getDefinitionByNameSample ():void {
            var ClassReference:Class 
= getDefinitionByName("flash.text.TextField") as Class;
            var instance:TextField 
= new ClassReference() as TextField;
            instance.autoSize 
= "left";
            instance.text 
= "我通过 getDefinitionByName 动态创建";
            addChild(instance);
        }


    }

}

动态获取类名称, 超类 (Superclass) 名称
有点像之前版本中的 typeof, 这个方法返回的是字符串

QUOTE:
------------------------------------------------------------
public function getQualifiedClassName(value:*):String
返回类的完全限定名 (fully qualified class name, qualified 我不知道怎么翻了..)

参数  value:* - 想要得到完全限定名的对象. 他可以是任何 ActionScript 类型, 对象实例, 简单类型如 uint 以及类类型.  
返回  String - 包含类的完全限定名的字符串
------------------------------------------------------------

QUOTE:
------------------------------------------------------------
public function getQualifiedSuperclassName(value:*):String
返回目标对象基类的完全限定名, 
本函数提供比 describeType 更简便的方法来获取基类的名称
提示: 本函数限制只寻找实例的继承层次,而 describeType() 函数使用的是类对象继承.
调用 describeType() 函数时返回的是基于超类以的类继承结构. 而 getQualifiedSuperclassName() 将忽略类的继承结构直接返回最接近的继承对象
例如, 理论上 String 类继承自 Class, 但调用 getQualifiedSuperclassName(String) 时返回的是 Object. 换句话说, 不管你传递的是类还是类的实例, 他们的返回值都是一样的

参数  value:* - 任何值.  
返回  String - 基类的完全限定名, 如果没有的话返回 null
------------------------------------------------------------

例子:

实例化新的 Sprite, 然后获取他的类名并输出

var sprite1:Sprite = new Sprite();
var classNameOfSprite:String = getQualifiedClassName(Sprite);
trace("Sprite 的类名 : " + classNameOfSprite); // Sprite 的类名 : flash.display::Sprite

超类

var superclassNameOfSprite:String = getQualifiedSuperclassName(Sprite);
trace("Sprite 的超类 (基类) 类名 : " + superclassNameOfSprite); // Sprite 的超类 (基类) 类名 : flash.display::DisplayObjectContainer

根据刚刚获取的类名使用 创建实例

var SpriteClass:Class = getDefinitionByName(classNameOfSprite) as Class;
var sprite2:Sprite = new SpriteClass() as Sprite;
trace("sprite2 通过 getDefinitionByName 创建 Sprite 实例");

画一个 100 x 100 的矩形并显示

sprite2.graphics.beginFill(0xFF00FF);
sprite2.graphics.drawRect(0, 0, 100, 100);
sprite2.graphics.endFill();
addChild(sprite2);

修改后的 ReflectionSample.as


package {
    
import flash.display.Sprite;
    
import flash.utils.getDefinitionByName;
    
import flash.utils.getQualifiedClassName;
    
import flash.utils.getQualifiedSuperclassName;

    
public class ReflectionSample extends Sprite
    
{
        
public function ReflectionSample () {
            getClassNameSample();
        }

        
        
/**    
         * 使用 flash.utils.getQualifiedClassName 和 getQualifiedSuperclassName 获取类名称, 并动态创建该类
         * 
         
*/
        
        
private function getClassNameSample ():void {
            var sprite1:Sprite 
= new Sprite();
            var classNameOfSprite:String 
= getQualifiedClassName(Sprite);
            trace(
"Sprite 的类名 : " + classNameOfSprite);
            
            var superclassNameOfSprite:String 
= getQualifiedSuperclassName(Sprite);
            trace(
"Sprite 的超类 (基类) 类名 : " + superclassNameOfSprite);
            
            var SpriteClass:Class 
= getDefinitionByName(classNameOfSprite) as Class;
            var sprite2:Sprite 
= new SpriteClass() as Sprite;
            trace(
"sprite2 通过 getDefinitionByName 创建 Sprite 实例");
            
            sprite2.graphics.beginFill(
0xFF00FF);
            sprite2.graphics.drawRect(
00100100);
            sprite2.graphics.endFill();
            addChild(sprite2);
        }
    

    }

}

获取类信息

QUOTE:
------------------------------------------------------------

public function describeType(value:*):XML
生成一个 XML 对象来描述参数中指定的 ActionScript 对象, 这个方法使 ActionScript 实现了反射编程的概念.

如果参数 value 是某类的实例, 那么返回的 XML 对象包含了此类中所有的实例属性, 但是不会包含任何的静态属性.
这种情况下你可以通过检查标签 <type> 中的 isStatic 属性来判断他, 当参数为某类的实例时, 这个值为 false.

要获取类的静态属性, 可以通过传递类本身到参数 value, 这样返回的 XML 对象不仅包括了类的静态属性, 也包括所有的实例属性.
实例属性被包含在 <factory> 标签中使它们和静态属性区别开来. 在这种情况下, <type> 标签的 isStatic 属性为 true.

提示: 如果你只需要获取对象的继承结构而不需要 describeType() 提供的其他信息, 可以使用 getQualifiedClassName() 和 getQualifiedSuperclassName() 来替代

下表描述了 describeType() 生成的 XML 的标签和属性 (按运行代码察看)
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=gb2312" >
< style  type ="text/css" >
{ font- size : 1em; }
table, td, th 
{ font-family : Verdana; border : 1px solid #000; border-collapse : collapse; background-color : #fefefe}
th 
{ background-color : #ccc; }
</ style >
</ head >
< body >
  
< table  width ="100%" >
      
< tr >< th > 标签 </ th >< th > 属性 </ th >< th > 说明 </ th ></ tr >
      
< tr >< td >< code > &lt; type &gt; </ code ></ td >< td >   </ td >< td > XML 对象的根标签 </ td ></ tr >
      
< tr >< td >   </ td >< td > name </ td >< td > ActionScript 对象 (ActionScript object) 类型 </ td ></ tr >
      
< tr >< td >   </ td >< td > base </ td >< td > 当前对象的直属超类, 如果当前 ActionScript 对象是类对象, 那那么该值为  < code > Class </ code > . </ td ></ tr >
      
< tr >< td >   </ td >< td > isDynamic </ td >< td > 如果当前 ActionScript 对象被定义为 dynamic, 那么该属性为  < code > true </ code > , 否则为  < code > false </ code > . 如果当前 ActionScript 对象是类对象, 那么该属性也为  < code > true </ code > , 因为 Class 类是 dynamic 的 </ td ></ tr >
      
< tr >< td >   </ td >< td > isFinal </ td >< td > 如果当前 ActionScript 对象被定义为 final, 那么该属性为  < code > true </ code > , 否则为  < code > false </ code ></ td ></ tr >
      
< tr >< td >   </ td >< td > isStatic </ td >< td > 如果当前 ActionScript 是类对象或者构造函数, 那么该属性为  < code > true </ code > , 否则为  < code > false </ code > . 该属性被命名为  < code > isStatic </ code >  是因为如果值为  < code > true </ code >  的话, 任何标签都不会被嵌套到  < code > factory </ code >  标签中 </ td ></ tr >
      
< tr >< td >< code > &lt; extendsClass &gt; </ code ></ td >< td >   </ td >< td > 使用  < code > extendsClass </ code >  标签分别存放当前 ActionScript 对象的超类 </ td ></ tr >
      
< tr >< td >   </ td >< td > type </ td >< td > 当前 ActionScript 对象所继承的超类的名字 </ td ></ tr >
      
< tr >< td >< code > &lt; implementsInterface &gt; </ code ></ td >< td >   </ td >< td > 使用  < code > implementsInterface </ code >  标签分别存放当前 ActionScript 对象, 以及他的超类所实现的接口 </ td ></ tr >
      
< tr >< td >   </ td >< td > type </ td >< td > 当前 ActionScript 所实现的接口的名字 </ td ></ tr >
      
< tr >< td >< code > &lt; accessor &gt; </ code ></ td >< td >   </ td >< td > 访问器是由 getter 和 setter 所定义的属性 </ td ></ tr >
      
< tr >< td >   </ td >< td > name </ td >< td > 该访问器的名字 </ td ></ tr >
      
< tr >< td >   </ td >< td > access </ td >< td > 该访问器的访问权限. 可能的值有  < code > readonly </ code > < code > writeonly </ code > , 和  < code > readwrite </ code > . </ td ></ tr >
      
< tr >< td >   </ td >< td > type </ td >< td > 该属性的数据类型 </ td ></ tr >
      
< tr >< td >   </ td >< td > declaredBy </ td >< td > 指示由哪个类定义了该访问器 </ td ></ tr >
      
< tr >< td >< code > &lt; constant &gt; </ code ></ td >< td >   </ td >< td > 常量是由  < code > const </ code >  所定义的属性 </ td ></ tr >
      
< tr >< td >   </ td >< td > name </ td >< td > 该常量的名称 </ td ></ tr >
      
< tr >< td >   </ td >< td > type </ td >< td > 该常量的数据类型 </ td ></ tr >
      
< tr >< td >< code > &lt; method &gt; </ code ></ td >< td >   </ td >< td > 方法是由类定义的一部分公开的函数 </ td ></ tr >
      
< tr >< td >   </ td >< td > name </ td >< td > 方法名 </ td ></ tr >
      
< tr >< td >   </ td >< td > declaredBy </ td >< td > 指示该方法由哪个类定义 </ td ></ tr >
      
< tr >< td >   </ td >< td > returnType </ td >< td > 方法的返回类型 </ td ></ tr >
      
< tr >< td >< code > &lt; parameter &gt; </ code ></ td >< td >   </ td >< td > 使用  < code > parameter </ code >  分别存放该方法的参数, 该标签被嵌套在  < code > &lt; method &gt; </ code >  中 </ td ></ tr >
      
< tr >< td >   </ td >< td > index </ td >< td > 一个数字指示当前参数被传递时所在函数中的位置, 如果是首个参数, 那么该值为 1 </ td ></ tr >
      
< tr >< td >   </ td >< td > type </ td >< td > 该参数的类型 </ td ></ tr >
      
< tr >< td >   </ td >< td > optional </ td >< td > 如果该参数为可选的话为  < code > true </ code > , 否则为  < code > false </ code ></ td ></ tr >
      
< tr >< td >< code > &lt; variable &gt; </ code ></ td >< td >   </ td >< td > 变量 (variable) 是由 var 语句所定义的变量 </ td ></ tr >
      
< tr >< td >   </ td >< td > name </ td >< td > 变量名 </ td ></ tr >
      
< tr >< td >   </ td >< td > type </ td >< td > 变量类型 </ td ></ tr >
      
< tr >< td >< code > &lt; factory &gt; </ code ></ td >< td >   </ td >< td > 如果当前 ActionScript 对象是类对象或者构造函数, 所有的实例属性将会被嵌套进该标签. 如果  < code > &lt; type &gt; </ code >  标签的  < code > isStatic </ code >  属性为  < code > true </ code > , 所有属性 (properties) 和方法 (method) 将不会被嵌套进改标签中. 该标签只出现在当前 ActionScript 对象是类对象或者构造函数的情况下 </ td ></ tr >
  
</ table >
</ body >
</ html >

另外, 由 describeType() 返回的类描述信息中只会含有所有可被访问的元素, 即所有非定义为 private 的元素.

解释了这么多, 我们来看看返回的 XML 格式
flash 的内置类 flash.display.Sprite :

trace(describeType(Sprite);

返回:


< type  name ="flash.display::Sprite"  base ="Class"  isDynamic ="true"  isFinal ="true"  isStatic ="true" >
  
< extendsClass  type ="Class" />
  
< extendsClass  type ="Object" />
  
< accessor  name ="prototype"  access ="readonly"  type ="*"  declaredBy ="Class" />
  
< factory  type ="flash.display::Sprite" >
    
< extendsClass  type ="flash.display::DisplayObjectContainer" />
    
< extendsClass  type ="flash.display::InteractiveObject" />
    
< extendsClass  type ="flash.display::DisplayObject" />
    
< extendsClass  type ="flash.events::EventDispatcher" />
    
< extendsClass  type ="Object" />
    
< implementsInterface  type ="flash.display::IBitmapDrawable" />
    
< implementsInterface  type ="flash.events::IEventDispatcher" />
    
< accessor  name ="hitArea"  access ="readwrite"  type ="flash.display::Sprite"  declaredBy ="flash.display::Sprite" />
    
< method  name ="startDrag"  declaredBy ="flash.display::Sprite"  returnType ="void" >
      
< parameter  index ="1"  type ="Boolean"  optional ="true" />
      
< parameter  index ="2"  type ="flash.geom::Rectangle"  optional ="true" />
    
</ method >
    
< accessor  name ="buttonMode"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::Sprite" />
    
< accessor  name ="graphics"  access ="readonly"  type ="flash.display::Graphics"  declaredBy ="flash.display::Sprite" />
    
< accessor  name ="soundTransform"  access ="readwrite"  type ="flash.media::SoundTransform"  declaredBy ="flash.display::Sprite" />
    
< method  name ="stopDrag"  declaredBy ="flash.display::Sprite"  returnType ="void" />
    
< accessor  name ="dropTarget"  access ="readonly"  type ="flash.display::DisplayObject"  declaredBy ="flash.display::Sprite" />
    
< accessor  name ="useHandCursor"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::Sprite" />
    
< method  name ="getChildAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
      
< parameter  index ="1"  type ="int"  optional ="false" />
    
</ method >
    
< method  name ="addChild"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< method  name ="swapChildren"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="void" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
      
< parameter  index ="2"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< method  name ="getChildByName"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
      
< parameter  index ="1"  type ="String"  optional ="false" />
    
</ method >
    
< method  name ="getObjectsUnderPoint"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="Array" >
      
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
    
</ method >
    
< accessor  name ="textSnapshot"  access ="readonly"  type ="flash.text::TextSnapshot"  declaredBy ="flash.display::DisplayObjectContainer" />
    
< method  name ="removeChildAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
      
< parameter  index ="1"  type ="int"  optional ="false" />
    
</ method >
    
< method  name ="getChildIndex"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="int" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< method  name ="areInaccessibleObjectsUnderPoint"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
    
</ method >
    
< accessor  name ="mouseChildren"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObjectContainer" />
    
< method  name ="removeChild"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< method  name ="setChildIndex"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="void" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
      
< parameter  index ="2"  type ="int"  optional ="false" />
    
</ method >
    
< method  name ="contains"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< method  name ="addChildAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
      
< parameter  index ="2"  type ="int"  optional ="false" />
    
</ method >
    
< accessor  name ="numChildren"  access ="readonly"  type ="int"  declaredBy ="flash.display::DisplayObjectContainer" />
    
< method  name ="swapChildrenAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="void" >
      
< parameter  index ="1"  type ="int"  optional ="false" />
      
< parameter  index ="2"  type ="int"  optional ="false" />
    
</ method >
    
< accessor  name ="tabChildren"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObjectContainer" />
    
< accessor  name ="tabEnabled"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::InteractiveObject" />
    
< accessor  name ="doubleClickEnabled"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::InteractiveObject" />
    
< accessor  name ="contextMenu"  access ="readwrite"  type ="flash.ui::ContextMenu"  declaredBy ="flash.display::InteractiveObject" />
    
< accessor  name ="accessibilityImplementation"  access ="readwrite"  type ="flash.accessibility::AccessibilityImplementation"  declaredBy ="flash.display::InteractiveObject" >
      
< metadata  name ="Inspectable" >
        
< arg  key ="environment"  value ="none" />
      
</ metadata >
    
</ accessor >
    
< accessor  name ="mouseEnabled"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::InteractiveObject" />
    
< accessor  name ="focusRect"  access ="readwrite"  type ="Object"  declaredBy ="flash.display::InteractiveObject" />
    
< accessor  name ="tabIndex"  access ="readwrite"  type ="int"  declaredBy ="flash.display::InteractiveObject" />
    
< accessor  name ="mask"  access ="readwrite"  type ="flash.display::DisplayObject"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="scaleX"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="scaleY"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< method  name ="getRect"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Rectangle" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< accessor  name ="mouseY"  access ="readonly"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="alpha"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="x"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="name"  access ="readwrite"  type ="String"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="y"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="root"  access ="readonly"  type ="flash.display::DisplayObject"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="width"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="stage"  access ="readonly"  type ="flash.display::Stage"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="loaderInfo"  access ="readonly"  type ="flash.display::LoaderInfo"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="transform"  access ="readwrite"  type ="flash.geom::Transform"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="height"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< method  name ="localToGlobal"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Point" >
      
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
    
</ method >
    
< accessor  name ="filters"  access ="readwrite"  type ="Array"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="blendMode"  access ="readwrite"  type ="String"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="rotation"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< method  name ="hitTestObject"  declaredBy ="flash.display::DisplayObject"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< accessor  name ="scale9Grid"  access ="readwrite"  type ="flash.geom::Rectangle"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="accessibilityProperties"  access ="readwrite"  type ="flash.accessibility::AccessibilityProperties"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="scrollRect"  access ="readwrite"  type ="flash.geom::Rectangle"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="cacheAsBitmap"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObject" />
    
< method  name ="globalToLocal"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Point" >
      
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
    
</ method >
    
< method  name ="getBounds"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Rectangle" >
      
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
</ method >
    
< accessor  name ="opaqueBackground"  access ="readwrite"  type ="Object"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="parent"  access ="readonly"  type ="flash.display::DisplayObjectContainer"  declaredBy ="flash.display::DisplayObject" />
    
< method  name ="hitTestPoint"  declaredBy ="flash.display::DisplayObject"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="Number"  optional ="false" />
      
< parameter  index ="2"  type ="Number"  optional ="false" />
      
< parameter  index ="3"  type ="Boolean"  optional ="true" />
    
</ method >
    
< accessor  name ="visible"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObject" />
    
< accessor  name ="mouseX"  access ="readonly"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
    
< method  name ="willTrigger"  declaredBy ="flash.events::EventDispatcher"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="String"  optional ="false" />
    
</ method >
    
< method  name ="removeEventListener"  declaredBy ="flash.events::EventDispatcher"  returnType ="void" >
      
< parameter  index ="1"  type ="String"  optional ="false" />
      
< parameter  index ="2"  type ="Function"  optional ="false" />
      
< parameter  index ="3"  type ="Boolean"  optional ="true" />
    
</ method >
    
< method  name ="toString"  declaredBy ="flash.events::EventDispatcher"  returnType ="String" />
    
< method  name ="addEventListener"  declaredBy ="flash.events::EventDispatcher"  returnType ="void" >
      
< parameter  index ="1"  type ="String"  optional ="false" />
      
< parameter  index ="2"  type ="Function"  optional ="false" />
      
< parameter  index ="3"  type ="Boolean"  optional ="true" />
      
< parameter  index ="4"  type ="int"  optional ="true" />
      
< parameter  index ="5"  type ="Boolean"  optional ="true" />
    
</ method >
    
< method  name ="dispatchEvent"  declaredBy ="flash.events::EventDispatcher"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="flash.events::Event"  optional ="false" />
    
</ method >
    
< method  name ="hasEventListener"  declaredBy ="flash.events::EventDispatcher"  returnType ="Boolean" >
      
< parameter  index ="1"  type ="String"  optional ="false" />
    
</ method >
  
</ factory >
</ type >

真是又臭又长啊. :o, 根据帮助中的描述, 所有的实例属性都被嵌套在了 <factory> 标签里.

我们再试一下获取实例的信息 :

var sprite1:Sprite = new Sprite();
var instanceInfo:XML = describeType(sprite1);

返回 :


< type  name ="flash.display::Sprite"  base ="flash.display::DisplayObjectContainer"  isDynamic ="false"  isFinal ="false"  isStatic ="false" >
  
< extendsClass  type ="flash.display::DisplayObjectContainer" />
  
< extendsClass  type ="flash.display::InteractiveObject" />
  
< extendsClass  type ="flash.display::DisplayObject" />
  
< extendsClass  type ="flash.events::EventDispatcher" />
  
< extendsClass  type ="Object" />
  
< implementsInterface  type ="flash.display::IBitmapDrawable" />
  
< implementsInterface  type ="flash.events::IEventDispatcher" />
  
< accessor  name ="hitArea"  access ="readwrite"  type ="flash.display::Sprite"  declaredBy ="flash.display::Sprite" />
  
< method  name ="startDrag"  declaredBy ="flash.display::Sprite"  returnType ="void" >
    
< parameter  index ="1"  type ="Boolean"  optional ="true" />
    
< parameter  index ="2"  type ="flash.geom::Rectangle"  optional ="true" />
  
</ method >
  
< accessor  name ="buttonMode"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::Sprite" />
  
< accessor  name ="graphics"  access ="readonly"  type ="flash.display::Graphics"  declaredBy ="flash.display::Sprite" />
  
< accessor  name ="soundTransform"  access ="readwrite"  type ="flash.media::SoundTransform"  declaredBy ="flash.display::Sprite" />
  
< method  name ="stopDrag"  declaredBy ="flash.display::Sprite"  returnType ="void" />
  
< accessor  name ="dropTarget"  access ="readonly"  type ="flash.display::DisplayObject"  declaredBy ="flash.display::Sprite" />
  
< accessor  name ="useHandCursor"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::Sprite" />
  
< method  name ="getChildAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
    
< parameter  index ="1"  type ="int"  optional ="false" />
  
</ method >
  
< method  name ="addChild"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< method  name ="swapChildren"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="void" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
< parameter  index ="2"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< method  name ="getChildByName"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
    
< parameter  index ="1"  type ="String"  optional ="false" />
  
</ method >
  
< method  name ="getObjectsUnderPoint"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="Array" >
    
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
  
</ method >
  
< accessor  name ="textSnapshot"  access ="readonly"  type ="flash.text::TextSnapshot"  declaredBy ="flash.display::DisplayObjectContainer" />
  
< method  name ="removeChildAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
    
< parameter  index ="1"  type ="int"  optional ="false" />
  
</ method >
  
< method  name ="getChildIndex"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="int" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< method  name ="areInaccessibleObjectsUnderPoint"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
  
</ method >
  
< accessor  name ="mouseChildren"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObjectContainer" />
  
< method  name ="removeChild"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< method  name ="setChildIndex"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="void" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
< parameter  index ="2"  type ="int"  optional ="false" />
  
</ method >
  
< method  name ="contains"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< method  name ="addChildAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="flash.display::DisplayObject" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
    
< parameter  index ="2"  type ="int"  optional ="false" />
  
</ method >
  
< accessor  name ="numChildren"  access ="readonly"  type ="int"  declaredBy ="flash.display::DisplayObjectContainer" />
  
< method  name ="swapChildrenAt"  declaredBy ="flash.display::DisplayObjectContainer"  returnType ="void" >
    
< parameter  index ="1"  type ="int"  optional ="false" />
    
< parameter  index ="2"  type ="int"  optional ="false" />
  
</ method >
  
< accessor  name ="tabChildren"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObjectContainer" />
  
< accessor  name ="tabEnabled"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::InteractiveObject" />
  
< accessor  name ="doubleClickEnabled"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::InteractiveObject" />
  
< accessor  name ="contextMenu"  access ="readwrite"  type ="flash.ui::ContextMenu"  declaredBy ="flash.display::InteractiveObject" />
  
< accessor  name ="accessibilityImplementation"  access ="readwrite"  type ="flash.accessibility::AccessibilityImplementation"  declaredBy ="flash.display::InteractiveObject" >
    
< metadata  name ="Inspectable" >
      
< arg  key ="environment"  value ="none" />
    
</ metadata >
  
</ accessor >
  
< accessor  name ="mouseEnabled"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::InteractiveObject" />
  
< accessor  name ="focusRect"  access ="readwrite"  type ="Object"  declaredBy ="flash.display::InteractiveObject" />
  
< accessor  name ="tabIndex"  access ="readwrite"  type ="int"  declaredBy ="flash.display::InteractiveObject" />
  
< accessor  name ="mask"  access ="readwrite"  type ="flash.display::DisplayObject"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="scaleX"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="scaleY"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< method  name ="getRect"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Rectangle" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< accessor  name ="mouseY"  access ="readonly"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="alpha"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="x"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="name"  access ="readwrite"  type ="String"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="y"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="root"  access ="readonly"  type ="flash.display::DisplayObject"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="width"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="stage"  access ="readonly"  type ="flash.display::Stage"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="loaderInfo"  access ="readonly"  type ="flash.display::LoaderInfo"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="transform"  access ="readwrite"  type ="flash.geom::Transform"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="height"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< method  name ="localToGlobal"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Point" >
    
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
  
</ method >
  
< accessor  name ="filters"  access ="readwrite"  type ="Array"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="blendMode"  access ="readwrite"  type ="String"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="rotation"  access ="readwrite"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< method  name ="hitTestObject"  declaredBy ="flash.display::DisplayObject"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< accessor  name ="scale9Grid"  access ="readwrite"  type ="flash.geom::Rectangle"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="accessibilityProperties"  access ="readwrite"  type ="flash.accessibility::AccessibilityProperties"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="scrollRect"  access ="readwrite"  type ="flash.geom::Rectangle"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="cacheAsBitmap"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObject" />
  
< method  name ="globalToLocal"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Point" >
    
< parameter  index ="1"  type ="flash.geom::Point"  optional ="false" />
  
</ method >
  
< method  name ="getBounds"  declaredBy ="flash.display::DisplayObject"  returnType ="flash.geom::Rectangle" >
    
< parameter  index ="1"  type ="flash.display::DisplayObject"  optional ="false" />
  
</ method >
  
< accessor  name ="opaqueBackground"  access ="readwrite"  type ="Object"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="parent"  access ="readonly"  type ="flash.display::DisplayObjectContainer"  declaredBy ="flash.display::DisplayObject" />
  
< method  name ="hitTestPoint"  declaredBy ="flash.display::DisplayObject"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="Number"  optional ="false" />
    
< parameter  index ="2"  type ="Number"  optional ="false" />
    
< parameter  index ="3"  type ="Boolean"  optional ="true" />
  
</ method >
  
< accessor  name ="visible"  access ="readwrite"  type ="Boolean"  declaredBy ="flash.display::DisplayObject" />
  
< accessor  name ="mouseX"  access ="readonly"  type ="Number"  declaredBy ="flash.display::DisplayObject" />
  
< method  name ="willTrigger"  declaredBy ="flash.events::EventDispatcher"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="String"  optional ="false" />
  
</ method >
  
< method  name ="removeEventListener"  declaredBy ="flash.events::EventDispatcher"  returnType ="void" >
    
< parameter  index ="1"  type ="String"  optional ="false" />
    
< parameter  index ="2"  type ="Function"  optional ="false" />
    
< parameter  index ="3"  type ="Boolean"  optional ="true" />
  
</ method >
  
< method  name ="toString"  declaredBy ="flash.events::EventDispatcher"  returnType ="String" />
  
< method  name ="addEventListener"  declaredBy ="flash.events::EventDispatcher"  returnType ="void" >
    
< parameter  index ="1"  type ="String"  optional ="false" />
    
< parameter  index ="2"  type ="Function"  optional ="false" />
    
< parameter  index ="3"  type ="Boolean"  optional ="true" />
    
< parameter  index ="4"  type ="int"  optional ="true" />
    
< parameter  index ="5"  type ="Boolean"  optional ="true" />
  
</ method >
  
< method  name ="dispatchEvent"  declaredBy ="flash.events::EventDispatcher"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="flash.events::Event"  optional ="false" />
  
</ method >
  
< method  name ="hasEventListener"  declaredBy ="flash.events::EventDispatcher"  returnType ="Boolean" >
    
< parameter  index ="1"  type ="String"  optional ="false" />
  
</ method >
</ type >

所有的标签与之前 factory 标签中的内容是一样的

现在我们使用 describeType 来遍历之前 Dummy 类中的元素

实例化:

var dummy:Dummy = new Dummy();

获取实例信息:

var instanceInfo:XML = describeType(dummy);

把所有的属性取出来, 包括访问器和变量, 并且访问器不可为只写:

var properties:XMLList = instanceInfo..accessor.(@access != "writeonly") + instanceInfo..variable;

此时 properties 里就有所有的属性名了. 最后我们遍历这个 XMLList

for each (var propertyInfo:XML in properties) {
    
    // 取出属性名
    var propertyName:String = propertyInfo.@name;
    
    // 根据属性名来访问
    trace(dummy[propertyName]);
}

这样 dummy 就被 "遍历" 出了~

完整代码:


var dummy:Dummy = new Dummy();
var instanceInfo:XML 
= describeType(dummy);
var properties:XMLList 
= instanceInfo..accessor.(@access != "writeonly"+ instanceInfo..variable;
for each (var propertyInfo:XML in properties) {
    var propertyName:String 
= propertyInfo.@name;
    trace(dummy[propertyName]);
}

这样我们可以专门写一个类, 负责获取类信息, 详细见类中注释
TypeDescriptor.as, 负责获取信息


package
{
    
import flash.utils.describeType;
    
import flash.utils.getQualifiedClassName;
    
import flash.utils.getDefinitionByName;
    
    
/**
     * 使用 flash.utils.describeType 获取类详细信息并缓存
     * 
@author kakera
     * 
     
*/

    
public class TypeDescriptor
    
{
        
        
/**
        * 缓存已经反射过了的对象
        
*/

        
private static var typeCache:Object = new Object();

        
        
        
/**
         * 获取类信息
         * 
@param target 要获取的目标对象
         * 
@return TypeDescriptorEntry 实例
         * 
         
*/

        
public static function describeType (target:*):TypeDescription {

            var className:String 
= getQualifiedClassName(target);            

            
/**
            * 检查缓存中是否已经有目标对象项, 如果有就返回缓存中的内容
            
*/

            
if (className in typeCache)
                
return typeCache[className];
                
            
            
/**
            * 暂存属性列表
            
*/

            var propertyNames:Array 
= [];
            

            
/**
            * 获取类信息, 如果传入的是实例则获取实例类型的类信息
            
*/

            var typeInfo:XML 
= flash.utils.describeType(target is Class ? target : getDefinitionByName(className) as Class);
            
            
            
/**
            * 获取类中所有的属性和访问器
            
*/

            var properties:XMLList 
= typeInfo.factory..accessor.(@access != "writeonly"+ typeInfo..variable;

            
            
/**
            * 遍历并存放到 propertyNames 中
            
*/

            
for each (var propertyInfo:XML in properties)
                propertyNames.push(propertyInfo.@name);
                
            
            
/**
            * 创建 TypeDescriptorEntry 的实例并把 propertyNames 等属性丢进去
            
*/

            var entry:TypeDescription 
= new TypeDescription();
            entry.name 
= className;
            entry.properties 
= propertyNames;
            entry.typeInfo 
= typeInfo;
            
            
            
/**
            * 缓存到 typeCache 中以便下次从缓存中读取
            
*/

            typeCache[className] 
= entry;
            
            
return entry;
        }

     
        
/**
         * 静态类无须实例化
         * 
@return 
         * 
         
*/

        
public function TypeDescriptor () { }
    }

}

TypeDescription.as, 负责保存信息

package
{
    
    
public class TypeDescription
    
{
        
        
/**
        * 类的属性列表, 包括访问器 (accessor) 和变量 (variable)
        
*/

        
public var properties:Array; /* of String */
            
        
        
/**
        * 类名
        
*/

        
public var name:String;
        


        
/**
        * 由 flash.utils.describeType() 获取的原始 XML 数据
        
*/

        
public var typeInfo:XML;
        

        
public function TypeDescription () { }
    }

}

你可能感兴趣的:(ActionScript 3中的类反射)