Recently I faced this problem: how to get if a Class is extending another one or implementing an interface?
this is the specific case:
function checkType(toCheck:Class,typeClass:Class=null,typeInterface:Class=null):Boolean
{
// if an instance of toCheck is a typeClass or a typeInterface
// return true
// else
// return false
}
The task is quite simple, the first solution would be get an instance of toCheck and use the is operator to actually check the type…but this would mean both a waste of resources and an “unwanted behaviour generator” (just think about a parser class instantiated without a real need or something like that).
Nope, that solution sucks.
Let’s try something better, let’s make the player inform us which is the toCheck class structure, let’s use describeType.
describeType is a wonderful function you can find in flash.utils package, it examines an untyped object and returns an xml document containing the description of that type (more details at adobe livedocs)…something like this:
NOTE: click on “view code” to see the real xml document, my wp is escaping tags chars <> …:\
<type name="flash.events::EventDispatcher" 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.events::EventDispatcher">
<metadata name="Event">
<arg key="name" value="deactivate"/>
<arg key="type" value="flash.events.Event"/>
</metadata>
<metadata name="Event">
<arg key="name" value="activate"/>
<arg key="type" value="flash.events.Event"/>
</metadata>
<extendsClass type="Object"/>
<implementsInterface type="flash.events::IEventDispatcher"/>
<constructor>
<parameter index="1" type="*" optional="true"/>
</constructor>
<method name="willTrigger" declaredBy="flash.events::EventDispatcher" returnType="Boolean">
<parameter index="1" type="String" optional="false"/>
</method>
<method name="hasEventListener" 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="dispatchEvent" declaredBy="flash.events::EventDispatcher" returnType="Boolean">
<parameter index="1" type="flash.events::Event" optional="false"/>
</method>
<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="toString" declaredBy="flash.events::EventDispatcher" returnType="String"/>
</factory>
</type>
As you can see in this EventDispatcher type description there are two nodes witch are fitting the task’s purposes:
<extendsClass> and <implementsInterface>
Those nodes are repeated for each class or interface in the given class (toCheck) chain of inheritance and they contain the qualified class name string of the extended\implemented class\interface.
In this case EventDispatcher extendsClass type=’Object’ and implementsInterface type=’flash.events::IEventDispatcher’ …quite clear right?:) Now, back to the implementation:
function checkType(toCheck:Class,typeClass:Class=null,typeInterface:Class=null):Boolean
{
//gets the toCheck class type xml description
var _typeXML:XML=describeType(toCheck);
//gets the typeClass and typeInterface qualified class names
var _result:Boolean=false;
if (typeClass) {
// if toCheck is a typeClass
for each (var _extClass:XML in _typeXML.factory.elements('extendsClass')) {
if (_extClass.@type==getQualifiedClassName(typeClass)) {
_result=true;
break;
}
}
}
// do the same for typeInterface but checking 'implementsInterface' node
if (typeInterface) {
for each (var _impInterface:XML in _typeXML.factory.elements('extendsClass')) {
if (_impInterface.@type==getQualifiedClassName(typeInterface)) {
_result=true;
break;
}
}
}
return _result;
}
…and the task got done
stay tuned