Как проверить, является ли экземпляр класса динамическим типом в AS3?
В AS3, если класс помечен как динамический, новые свойства можно добавлять и удалять во время выполнения, просто устанавливая свойство или удаляя его с помощью delete
ключевое слово.
Я спрашиваю, есть ли более быстрый способ определить, является ли класс динамическим, чем вызов describeType
функция и проверка значения атрибута "isDynamic" на возвращенном узле верхнего уровня XML, например: <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 доступен только в проигрывателе отладки. Вот почему мне действительно нужно заранее проверить, является ли класс динамическим, чтобы можно было надежно прогнозировать и полностью избежать ошибки назначения. Я выберу правильную реализацию более быстрой.
2 ответа
Поскольку единственный правильный способ определить, можно ли назначить свойство, состоит в том, чтобы проверить, существует ли свойство и может ли оно быть создано, я решил сосредоточиться на оптимизации определения того, является ли экземпляр динамическим.
Хотя функция descriptionType может быть относительно медленной, мне действительно нужно вызывать ее только один раз для каждого типа, если я кеширую результаты. Затем я могу сохранить логический результат в словаре по имени типа или по ссылке на класс, а затем просто использовать гораздо более быстрые методы 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." );
Мое предложение состоит в том, чтобы пойти 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
, он пропустит этот перехват и будет перехвачен универсальным перехватом для всех других типов ошибок и отследит not the error you're looking for
,