2013-03-05 8 views
6

Ho un metodo che registra un messaggio ogni volta che viene chiamato. Vorrei che questo messaggio di registro indicasse se il metodo è stato chiamato direttamente o invocato usando super in una classe figlia.Determinare se il metodo ActionScript ha chiamato utilizzando super

class DoerOfWork { 
    public function doWork():void { 
     var calledWithSuper:Boolean; 

     calledWithSuper = ???; 

     trace("doWork called" + (calledWithSuper ? " (with super)." : ".")); 
    } 
} 

class SlowerDoerOfWork extends DoerOfWork { 
    public override function doWork():void { 
     for (var i:Number = 0; i < 321684; i++) { 
      // wait a moment 
     } 
     super.doWork(); 
    } 
} 

speravo che sarebbe stato possibile determinare se la classe di this aveva ignorato l'attuazione di doWork confrontando this.doWork-DoerOfWork.prototype.doWork.

Purtroppo questo non è possibile. I metodi non associati non sono accessibili da nessuna parte in ActionScript (la specifica elenca due tipi di funzioni: chiusure di funzioni e metodi associati). Non c'è nemmeno alcuna proprietà su istanze su MethodClosure che potrebbe identificare se due sono copie vincolate dello stesso metodo.

Come è possibile verificare se un metodo è stato sovrascritto o utilizzare un altro metodo per determinare se il metodo ActionScript attualmente in esecuzione è stato chiamato utilizzando super o chiamato direttamente?

risposta

3

È possibile ottenere un riferimento alla funzione attualmente in esecuzione come arguments.callee. Dal metodo questo sarà il MethodClosure di DoerOfWork().doWork() con this. Se doWork() non è stato sovrascritto, questo sarà uguale a this.doWork.

class DoerOfWork { 
    public function doWork():void { 
     var calledWithSuper:Boolean; 

     calledWithSuper = this.doWork == arguments.callee; 

     trace("doWork called" + (calledWithSuper ? " (with super)." : ".")); 
    } 
} 

Se si sta eseguendo in modalità non rigorosa, a quanto pare questo disabiliterà numero di argomenti per controllare la funzione corrente. (. Non ho controllato io stesso, non sono nemmeno sicuro di come disabilitare la modalità rigorosa in IntelliJ)

3

Se siete disposti a usare flash.utils.describeType(), contiene le informazioni di cui abbiamo bisogno:

<type name="Main.as$1::SlowerDoerOfWork" base="Main.as$1::DoerOfWork" 
     isDynamic="false" isFinal="false" isStatic="false"> 
    <extendsClass type="Main.as$1::DoerOfWork"/> 
    <extendsClass type="Object"/> 
    <method name="doWork" declaredBy="Main.as$1::SlowerDoerOfWork" 
      returnType="void"> 
    <metadata name="__go_to_definition_help"> 
     <arg key="pos" value="1170"/> 
    </metadata> 
    </method> 
    <metadata name="__go_to_definition_help"> 
    <arg key="pos" value="1103"/> 
    </metadata> 
</type> 

L'attributo declaredBy di ogni <method> nell'XML utilizza lo stesso formato di flash.utils.getQualifiedClassName e possiamo confrontarlo per determinare se la nostra implementazione è stata ignorata.

class DoerOfWork { 
    public function doWork():void { 
     var calledWithSuper:Boolean; 

     var currentImplementationFrom:String 
      = flash.utils.describeType(this).method.(@name=="doWork")[email protected]; 
     var thisImplementationFrom:String 
      = flash.utils.getQualifiedClassName(DoerOfWork); 

     calledWithSuper = currentImplementationFrom != thisImplementationFrom; 

     trace("doWork called" + (calledWithSuper ? " (with super)." : ".")); 
    } 
}