【问题标题】:How to test whether a class instance is a dynamic type in AS3?AS3中如何测试一个类实例是否为动态类型?
【发布时间】:2014-03-31 09:42:34
【问题描述】:

在 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 方法的唯一问题是我不知道分配是否因为无法分配属性而失败,或者属性设置器中是否发生了其他错误。即使捕获错误并检查其类型也不会告诉我错误是否发生在这个精确的点(与此设置器调用链中的其他设置器相反),因为 getStackTrace 方法仅在调试播放器中可用。这就是为什么我真的需要预先检查该类是否是动态的,以便可以可靠地预测并完全避免分配失败。我会选择正确的实现而不是更快的实现。

【问题讨论】:

    标签: actionscript-3 flash properties dynamic-class


    【解决方案1】:

    由于判断属性是否可以赋值的唯一正确方法是检查属性是否存在以及属性是否可以创建,所以我决定重点优化判断实例是否为动态的。

    虽然 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." );
    

    【讨论】:

    • 另外,getQualifiedClassName 的运行速度比 describeType 快大约 3000 倍。 getQualifiedClassName 100,000 次迭代耗时 51 毫秒,而 describeType 仅 1000 次迭代耗时 1528 毫秒。
    【解决方案2】:

    我的建议是走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 时,它将跳过该捕获并被所有其他错误类型的通用捕获捕获并跟踪not the error you're looking for

    【讨论】:

    • 这仍然没有告诉我该属性设置失败。它告诉 some 属性,可能嵌套在属性设置器的调用链深处,未能设置。我还必须检查堆栈跟踪以确保它确实发生在这个特定的分配中。
    • 我拥有的“参考”实现包含一个基础对象和一个属性名称,它的“值”访问器旨在抽象出属性名称和同名子对象之间的区别。如果需要子实例,它将设置子实例和属性中的一个/两者,如果成功按名称设置子实例,它将忽略丢失的属性。这就是为什么我试图检测一个可以被设计忽略的非常具体的允许故障。与对 isDynamic 的显式检查不同,简单地捕获错误仍然需要确认错误发生的位置。
    • 我仍在投票,因为它至少可以确定要检查的错误,并且是 try/catch 方法的良好开端。不幸的是,getStackTrace 只能在调试模式下工作:stackoverflow.com/a/149188/88409
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 2020-12-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 2011-01-27
    相关资源
    最近更新 更多