如何测试类实例是否是AS3中的动态类型?

时间:2014-02-27 18:34:51

标签: actionscript-3 flash properties dynamic-class

在AS3中,如果某个类被标记为动态,则可以在运行时添加和删除新属性,方法是设置属性或使用delete关键字将其删除。

我问是否有更快的方法来确定一个类是否是动态的,而不是调用describeType函数并检查返回的顶级XML节点上的“isDynamic”属性值,例如:{{ 1}}。

我怀疑有一种更快的方法,但我真正需要做的就是尝试分配属性值(如果存在或可以创建)。

<type name="flash.display::MovieClip" base="Class" isDynamic="true" isFinal="true" isStatic="true">

也许我最好只将赋值包装在try / catch块中,并假设在赋值失败时类不是动态的。如果成功,我不关心它是否是动态的,因为目标是简单地分配属性值(如果存在或可以添加)。

//The "base is dynamic" test is pseudo-code since it's not valid
if (base.hasOwnProperty(propertyName) || (base is dynamic))
    base[propertyName] = value;
else
    throw new Error( "Property " + propertyName + " does not exist and cannot be created." );

我对try / catch方法的唯一问题是我不知道赋值是否失败,因为无法分配属性或者属性setter中是否发生了其他错误。即使捕获错误并检查其类型也不会告诉我错误是否发生在这个精确点(与此setter调用链中的其他一些setter相反),因为getStackTrace方法仅在调试播放器中可用。这就是为什么我真的需要检查该类是否是预先动态的,因此可以可靠地预测和完全避免分配失败。我将选择更快的正确实施。

2 个答案:

答案 0 :(得分:1)

我的建议是走try/catch路线。但是,您实际上可以检查它是否失败,因为无法通过检查通用errorID上的Error来分配属性,或者您可以捕获该特定内容赶上别人之前的错误。您要找的是1056 ReferenceError

以下是我提到的第二种方法的示例:

var instanciatedSprite:Sprite = new Sprite();
var nonInstanciatedSprite:Sprite;
var dynamicMovieClip:MovieClip = new MovieClip();

for each(var obj:Object in [dynamicMovieClip, instanciatedSprite, nonInstanciatedSprite]){
    try{
        obj["abc"] = "abc";
    }
    catch(e:ReferenceError){
        trace("property did not exist and class is not dynamic");
    }
    catch(e:Error){
        trace("not the error you're looking for");
    }
}

当它尝试将属性分配给property did not exist and class is not dynamic时,将首先跟踪instanciatedSprite。然后,当它到达nonInstanciatedSprite时,它将跳过该catch并被所有其他Error类型的泛型catch捕获并追踪not the error you're looking for

答案 1 :(得分:0)

由于确定是否可以分配属性的唯一正确方法是检查属性是否存在以及是否可以创建属性,因此我决定专注于优化实例是否是动态的确定。

虽然describeType函数可能相对较慢,但如果我缓存结果,我实际上只需要为每个类型调用一次。然后我可以通过类型名称或类引用将布尔结果存储在字典中,然后使用更快的函数getQualifiedClassName和/或getDefinitionByName方法来查找类是否是动态的。

public class ClassUtils
{
    static var typeDescriptions:Dictionary;
    static var isTypeDynamic:Dictionary;

    public function isDynamic( instanceOrClass:* ):Boolean
    {
        var qname:String = getQualifiedClassName(instanceOrClass);
        var isDynamic:* = isTypeDynamic[qname];
        if (isDynamic === undefined) //only explicitly untyped variables can hold the value undefined with strict equality
        {
            var desc:XML = getCachedTypeDescription( qname );
            isDynamic = Boolean(desc.@isDynamic);
            isTypeDynamic[qname] = isDynamic;
        }
        return isDynamic;
    }

    public function getCachedTypeDescription( qname:String ):XML
    {
        var desc:* = typeDescriptions[qname];
        if (desc === undefined) //only explicitly untyped variables can hold the value undefined with strict equality
        {
            desc = describeType( type );
            typeDescriptions[qname] = desc;
        }
        return desc;
    }
 }

这反过来将使我的原始实现能够快速有效地运行:

if (base.hasOwnProperty(propertyName) || (ClassUtils.isDynamic(base))
    base[propertyName] = value;
else
    throw new Error( "Property " + propertyName + " does not exist and cannot be created." );