AS3在运行时设置更改类类型

时间:2011-03-14 11:20:03

标签: flash actionscript-3 actionscript dynamic runtime

我有一个类并使用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"/>
    <extendsClass type="Object"/>
    <implementsInterface type="flash.events::IEventDispatcher"/>
    </type>

是否有可能在运行时覆盖此信息,例如类型。@ isDynamic,以及extendsClass。@ type。 没有字节码?

5 个答案:

答案 0 :(得分:3)

这样做的最佳替代方法是使用合成并只封装您需要的类。这样您就可以避免使用动态关键字以及更改扩展值的需要。

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;
    }
}

答案 1 :(得分:0)

有办法做你想做的事,但在我解释之前,我想说几件事:

1)这不是最佳实践 - 有一个原因是代码以它的工作方式工作,并且只要你觉得需要改变AS3的整个工作方式(比如在运行时将类更改为动态,例如,那么坐下来弄清楚这是否真的是最好的事情是一个非常好的主意。可能存在的设计模式可以帮助您解决您尝试解决的具体问题。

2)如果您使用我即将与您分享的秘密,那么其他用户几乎无法理解您的代码。也许你在一个爱好项目上独自工作,这很好 - 但如果你是一个团队,或者如果你是一个很长一段时间对一个非常复杂的项目进行更新的人之一,那么为每个接触过的人做好准备在你诅咒你的名字之后这个代码。 :)

那说,准备好了吗?

您可以通过修改.prototype属性来更改类的行为。例如,假设我的MyClass类只有一个方法,“myMethod()”。但无论出于何种原因,在运行时我需要在类中添加一个新方法(“myNewMethod()”)。

我通过在我正在使用的任何类中创建一个名为“myNewMethod()”的函数来实现这一点。然后我将对该函数的引用传递给MyClass的原型。请注意,因为您在这里弯曲规则,所以您将不得不使用字符串文字作为函数名称来避免编译器错误。

以下是代码示例:

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!

非常酷,呵呵?

那就是说,除非你知道你在做什么,否则不要在生产规范中这样做!有更好的方法可以获得类似的结果,你的队友可能会感谢你。

答案 2 :(得分:0)

不,xml基于加载类时字节码中的特征。您不能通过加载新的类来覆盖类,因此您会遇到类的第一个定义。

答案 3 :(得分:0)

在运行时扩展两个类不是问题。 我最后一个例子,但它不是无错误的atm,因为我现在不需要它。

使用describe类型非常容易。我不能摆脱动态但这不是问题。 我在这台电脑上没有我的例子,这是我可以从脑海中解决的问题:

//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;
}

它将成为200-300线解决方案。

答案 4 :(得分:0)

现在它的工作。最后一篇文章是一些部分香蕉可疑的WHAT。 这就是我放弃另一封信的原因。对于访问者我必须走很长的路。 oldschool javascript ...

包     {     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;
        }


    }

}


    {

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';
        }   


    }

}