开发者

AS3 Setting changing class type at runtime

i have a class and trace its type with flash.utils.describeType(this)

class Data extends EventDispatcher
        {
        public function Data()
            {
            //constructor
            }

        public override function toString():String
            {
            return describeType(this);
            }
        }


<type name="Data" base="flash.events::EventDispatcher" isDynamic="false" isFinal="false" isStatic="false">
    <extendsClass type="flash.events::EventDispatcher"开发者_如何学Go/>
    <extendsClass type="Object"/>
    <implementsInterface type="flash.events::IEventDispatcher"/>
    </type>

Is it possible to override this information e.g type.@isDynamic, as well as extendsClass.@type, at runtime? without bytecode?


The best alternative to doing this, is to use composition and just encapsulate the class you need. That way you can avoid the dynamic keyword and the need to change the extension value.

public class Data extends TheClassYouNeedToExtend
{
    private var encapsulated : TheRealData;

    private var value : int;

    public function Data()
    {
        encapsulated = new TheRealData;
    }

    public function get dynamicValue() : int
    {
        return value;
    }

    public function get dataValue() : int
    {
        return encapsulated.value;
    }
}


No, the xml is based on the traits in the bytecode when the class is loaded. You cannot override classes by loading in new ones, so you are stuck with the first definition of the class.


its not a problem to extend two classes at runtime. I worte an example last evenning but its not bugfree atm because im not going to need it now.

its very easy with describe type. i cant get rid of the dynamic but thats not a problem. i dont have my example on this pc, here is what i can make up from my mind:

//D == public dynamic class;
var C:Class = extend(D,EventDispatcher);


function _new(A)
{
if(A.prototype.extend)
  {
  //hehe
  for(var i in A.prototype.extend)
    {
    //BANG!
    //copy proterties
    }
  return new A();
  }
else return new A();
}


function extend(A,B,b=false)
{
var C = A;

if(!b)
 {
 C = xtend(C,B,xml.extendClass);
 C = xtend(C,A,xml.extendClass);
 }

C = copy(C,B,xml.constant);
C = copy(C,A,xml.constant);
C = copy(C,B,xml.variable);
C = copy(C,A,xml.variable);

return C;
}


function xtend(A,B,xml)
{
for(var i in xml)
    {
    var C:Class = Class(getDefinitionByName(xml[xml.length()-Number(i)-1]));
    A = extend(A,C,true);

    if(!A.prototype.extend) A.prototype.extend = [];
    A.prototype.extend.push(C);
    }

A.prototype.extend = A.prototype.extend.unique();
return A;
}


function copy(A,B,xml)
{
for each(var node in xml)
    A[node.@name] = B[node.@name];

return A;
}

its going to be a 200-300 line solution.


There is a way to do what you want to do, but before I explain it I'd like to say a few things:

1) This is NOT a best practice - there is a reason that code works the way it works, and any time you feel like you need to change the entire way AS3 works (like by changing a class to dynamic at runtime, for instance) then it's a very good idea to sit down and figure out if that's really the best thing to do. Odds are there's an existing design pattern that will help you solve the specific problem you're trying to solve.

2) If you use the secrets I'm about to share with you then it's going to become next to impossible for other users to make sense of your code. Maybe you're working solo on a hobby project and this is fine - but if you're on a team, or if you're one of a long set of people making updates to a very complex project, be prepared for everyone who touches this code after you do to curse your name. :)

That said, ready?

You can change the behavior of a class by modifying its .prototype property. For instance, let's say I have class MyClass which has only one method, "myMethod()". But for whatever reason, at runtime I need to add a new method ("myNewMethod()") to the class.

I do that by creating a function called "myNewMethod()" in whatever class I'm working in. Then I pass a reference to that function to the prototype of MyClass. Note that because you're bending the rules here you're going to have to use string literals as your function names to avoid compiler errors.

Here's a code sample:

var test1:MyClass = new MyClass();
test1.myMethod() // works just fine
test1.anotherMethod() // compiler error - this method does not exist in MyClass! Can't compile.

MyClass.prototype["anotherMethod"] = function ():void { trace("anotherMethod!"); }

test1.anotherMethod(); // error - as far as the compiler knows, anotherMethod doesn't exist. Still can't compile.

test1["anotherMethod"]() // this works!

Pretty cool, huh?

That said, DO NOT DO THIS IN PRODUCTION CODE UNLESS YOU KNOW WHAT YOU'RE DOING! There are better ways to achieve similar results, and your teammates will probably thank you.


now its working. The last post was someWHAT shameful for some part of the bananas. thats why i dropped another letter. for the accessors i had to go the long way. oldschool javascript...

package { import flash.display.DisplayObject; import flash.display.Sprite; import flash.events.Event; import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; import flash.utils.describeType;

public class Main extends Sprite 
    {

    public function Main():void 
        {
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
        }

    private function init(e:Event = null):void 
        {
        removeEventListener(Event.ADDED_TO_STAGE, init);

        var C:Class = Class(extend(D, Sprite));
        var O:Object = _new(C);

        var s:Sprite = new Sprite();
        O.addEventListener('asddas',event);
        O.dispatchEvent(new Event('asddas'));
        O.addChild(s);

        O.graphics.clear();
        O.graphics.beginFill(0x000000,1);
        O.graphics.lineStyle(1, 0x000000, 1, true, "none"); 
        O.graphics.drawRect(0, 0, 100, 100);
        O.graphics.endFill();       

        trace(O.getChildAt(0), O.numChildren, O.width, O.prototype.extend.width, O.hasEventListener('asddas'), O.willTrigger('asddas'), O.mouseY, O.mouseEnabled);

        addChild(O.prototype.extend);
        }   


    private function event(e:Object):void
        {
        trace(e.type);
        }

    private function _new(A:Class):Object
        {
        if (A.prototype.extend)
            {
            var O:Object = new A();
            var E:Object = new A.prototype.extend(); 
            var xml:XML = describeType(E);          
            trace(xml);

            O = copy(O, E, xml.method);
            O = copy(O, E, xml.variable);
            O = copy(O, E, xml.constant);
            O = copy(O, E, xml.accessor);

            O.prototype = { }; O.prototype.extend = E;
            return O;
            }
        else return new A(); //->
        }

    private function extend(A:Object, B:Object, b:Boolean = false):Object
        {
        var xml:XML = describeType(B);

        A.prototype.extend = B;
        A = copy(A, B, xml.constant);
        A = copy(A, B, xml.variable);
        A = copy(A, B, xml.method);
        A = copy(A, B, xml.accessor);

        return A;
        }

    private function copy(A:Object, B:Object, xml:XMLList):Object   
        {
        var node:XML

        for each(node in xml)
            {
            try { A[node.@name] = B[node.@name] } catch (e:Error) { trace('fail: '+node.@name) };
            }

        return A;
        }


    }

}

package
{

public dynamic class D
    {
    public static var abc:String = 'adsda';
    public const abd:String = '23223';
    private var width:Number;

    public function D() 
        {

        }

    public function toString():String 
        {
        return 'object';
        }   


    }

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜