Ultimate AS3 Fake Enums

I just can’t leave this thing alone. This is hopefully the last revision I’m going to make to my fake AS3 enum class (here’s the original posting, then two updates). This is inspired by commenter Mikko Korpela, who asked about an iteration ability. Well, that sounds like a fun idea! Let’s fill in some holes and bring it up to par with the enum support in C#.

Sorry it took me so long to get around to this Miko, but I’ve had my Flex work on hold for a while. But recently I did some Flash work at PopCap and it got me back in the mood again.

New Enum Features

Here’s my Ultimate AS3 Fake Enum class, which has the following new features:

  • Further type safety. Only the enum can construct its own constants now, via enum constructor protection. This should prevent people using the constants incorrectly (e.g. someone is incorrectly new’ing them up instead of using MyEnum.MyConstant).
  • Every constant now gets a zero-based index that corresponds to the order it is created in the class. Access via the Index accessor on the constant. Useful in serialization code, for example.
  • Added a new GetConstants method that returns an array of all the constants, where each constant’s slot in the array corresponds to its Index.
  • Added a new ParseConstant method that does the reverse of toString(). Given a constant’s Name, return the constant. Case sensitivity optional and off by default for convenience.

…all without any extra burden placed on the derivative class! I’m always interested in solutions that keep client code as clean as possible.

I also adjusted the code to my current AS3 coding standards, which is nearly the same as Microsoft’s C# standards. Note that I’d normally use Vector.<Enum> instead of the generic Array class, but I haven’t upgraded my Flex to the newest SDK yet.

The Code

Without further ado, here’s the new Enum.as file. Stick it in a package if you wish, and drop it wherever you like. No system setup is required to make it work.

package

{

import flash.utils.*;

public /*abstract*/ class Enum

{

public function get Name() :String { return _name; }

public function get Index() :int { return _index; }

public /*override*/ function toString() :String { return Name; }

public static function GetConstants(i_type :Class) :Array

{

var constants :EnumConstants = _enumDb[getQualifiedClassName(i_type)];

if (constants == null)

return null;

// return a copy to prevent caller modifications

return constants.ByIndex.slice();

}

public static function ParseConstant(

i_type :Class,

i_constantName :String,

i_caseSensitive :Boolean = false) :Enum

{

var constants :EnumConstants = _enumDb[getQualifiedClassName(i_type)];

if (constants == null)

return null;

var constant :Enum = constants.ByName[i_constantName.toLowerCase()];

if (i_caseSensitive && (constant != null) && (i_constantName != constant.Name))

return null;

return constant;

}

/*-----------------------------------------------------------------*/

/*protected*/ function Enum()

{

var typeName :String = getQualifiedClassName(this);

// discourage people new'ing up constants on their own instead

// of using the class constants

if (_enumDb[typeName] != null)

{

throw new Error(

"Enum constants can only be constructed as static consts " +

"in their own enum class " + "(bad type='" + typeName + "')");

}

// if opening up a new type, alloc an array for its constants

var constants :Array = _pendingDb[typeName];

if (constants == null)

_pendingDb[typeName] = constants = [];

// record

_index = constants.length;

constants.push(this);

}

protected static function initEnum(i_type :Class) :void

{

var typeName :String = getQualifiedClassName(i_type);

// can't call initEnum twice on same type (likely copy-paste bug)

if (_enumDb[typeName] != null)

{

throw new Error(

"Can't initialize enum twice (type='" + typeName + "')");

}

// no constant is technically ok, but it's probably a copy-paste bug

var constants :Array = _pendingDb[typeName];

if (constants == null)

{

throw new Error(

"Can't have an enum without any constants (type='" +

typeName + "')");

}

// process constants

var type :XML = flash.utils.describeType(i_type);

for each (var constant :XML in type.constant)

{

// this will fail to coerce if the type isn't inherited from Enum

var enumConstant :Enum = i_type[constant.@name];

Page 1 of 3 | Next page