问题
I have an established pattern for lazy loading data from a server via AMF.
private var _XeventDispatched:Boolean;
private var _X:ArrayCollection;
public function get X():ArrayCollection{
if(!_XeventDispatched && (_X==null || _X.length==0)){
var evt:Event = new Event();//whatever event is need for this data member
dispatcher.dispatchEvent(evt);
_XeventDispatched = true;
}
return _X;
}
public function set X(ac:ArrayCollection):void{
return _X;
}
This way the data is not loaded from the server until it is needed. (I'm using the Mate framework by the way, so when a UI is instanciated, and the injectors fire, they call this get method in the data manager class.)
What I'd like to do is create some kind of Metadata tag, similar to [Bindable] that will add the above methods in place of a public property.
[LazyLoaded(eventName="com.myCompany.LoadX")]
public var X:ArrayCollection;
Does the compiler have any hooks for this type of extension? It would save a lot of boiler plate code that is hard to read.
回答1:
As Flextra's has mentioned, one option is to use runtime reflection of the Metadata, and build your framework around this.
That's similar to how Lazy Loading is implented in dpHibernate (a Flex Lazy Loading framework which I'm a developer on). Specifically to get access to the getters and setters and intercept them with hooks for lazy loading, we make use of the [Managed]
metatag, and tweak it's behaviour, which gets the compiler to build the hooks in for you.
It's a bit of a hack, but it may help you. (And we've built a pretty successful framework on top of that hack).
Alternatively, you can write your own compiler extensions which use your Metadata, and performs AST modifications to generate that code for you. However, it's not for the faint-of-heart.
Although the hooks for these extensions have been around for many years now, there's very little out there about how to do it, and you'd need to work it out by looking through the existing source.
Luckily, the boffin's at Adobe have been eating their own dogfood with regards to the compiler extensions, and a few of the Flex 4 features (such as Skinning) has been implemented as compiler extenions, giving you a few more examples to work from.
The source for the compiler is available here.. It may pay to take a look at the code for the Managed extension as a good starting point.
Alternatively, take a look at the SkinPart extension, HostComponent extension or [Embed] (which Clement Wong - the original developer of the compiler - once mentioned as the best starting point in understanding compiler extensions).
回答2:
I think you want to use the keep--as3-metadata compiler argument. Something like this:
keep-as3-metadata+=LazyLoaded
回答3:
+1 Marty you lead me to this, but its different from your solution.
I've created a base class (BaseDataManager
) that all other Mate data managers can extend from, and in that class I've added the below code:
private var eventsDispatched:Array = new Array();
protected function lazyLoad(value:*, eventType:String):*{
if(!eventsDispatched[event] && (value==null || (value is IList && IList(value).length==0))){
var clazzName:String = eventType.substr(0, eventType.indexOf(":"));
var eventClazz:Class = Class(getDefinitionByName(clazzName));
var event:Event = new eventClazz(eventType);
dispatcher.dispatchEvent(event);
eventsDispatched[event] = true;
}
return value;
}
Then within each data manager, if the property is to be lazy loaded, this is their accessors:
private var _X:ArrayCollection;
public function get X():ArrayCollection{
return lazyLoad(_X, XLoadEvent.LOAD_EVENT_TYPE);
}
public function set X(value:ArrayCollection):void{
_X = value;
}
This way most of the ugly, hard to read code is hidden away from the dev, yet still accessible for debugging if any problems were to arise.
来源:https://stackoverflow.com/questions/7586256/actionscript-compiler-directive