如何在AS3中测试类实例是否为动态类型



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

我想问是否有比调用describeType函数并检查返回的顶级XML节点上的"isDynamic"属性值(例如:<type name="flash.display::MovieClip" base="Class" isDynamic="true" isFinal="true" isStatic="true">)更快的方法来确定类是否是动态的。

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

//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块中,并假设赋值失败时类不是动态的。如果它成功了,我不在乎它是否是动态的,因为目标是简单地分配属性值(如果存在或可以添加)。

try{base[propertyName] = value}catch(err:Error){/*property did not exist and class is not dynamic, or some other error occurred in the property setter*/}

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

我的建议是走try/catch路线。但是,实际上可以检查它是否失败,因为无法通过检查通用Error上的errorID来分配属性,或者可以在捕获其他错误之前捕获特定错误。你要找的是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");
}
}

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

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

尽管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." );

最新更新