Можно ли динамически создать экземпляр пользовательского класса в Action Script 3? - PullRequest
2 голосов
/ 12 января 2011

Я получил фабрику, где Action Script следует XML и строит из него иерархию DisplayObject.Это означает, что скрипт не знает заранее, с какими элементами он встретится в xml, и поэтому не знает, какие пользовательские фабричные классы ему понадобятся.

Я знаю, что возможно сделать что-то подобное:

var rect:*, className:String = "flash.geom.Rectangle";

if (ApplicationDomain.currentDomain.hasDefinition(className)) {         
    rect = new(getDefinitionByName(className));
}

И Прямоугольник экземпляр будет создан.Но как только я заменяю flash.geom.Rectangle на что-то определенное пользователем, например my.factory.Block , оно перестает работать, и если я закомментирую условное выражение, я получаю простое:* «Блок переменных не определен» ошибка.

Очевидным обходным решением будет создание экземпляра my.factory.Block (и всех других компонентов) перед активациейфабрика, но это как бы разрушает весь смысл фабрики динамических компонентов.

Конечно, у меня есть: import my.factory. *; инструкция в верхней части скрипта.

Есть ли более разумное решение для этого?

Ответы [ 5 ]

3 голосов
/ 12 января 2011

Как уже отмечали другие, проблема, скорее всего, заключается в том, что классы не включены в скомпилированный swf.Как указал Даниэль, импорта недостаточно, вам нужна ссылка на класс.Однако вам не нужно объявлять переменную, как сказал Cay, вы можете просто сделать следующее:

MyClass;

Хотя, если вы используете mxmlc для компиляции,вы можете использовать опцию -include, чтобы указать класс или классы, которые вы хотите принудительно включить в скомпилированный SWF.Хорошая вещь об этом - это не требует, чтобы у вас была ссылка в вашем коде.Это выглядит так:

- включает com.example.MyClass com.example.MyOtherClass

Если у вас действительно большой пакет классов, который вы хотите включить, но не хотите писатьИз имени класса для каждого класса вы можете скомпилировать пакет как SWC, используя compc, и использовать опцию -include-library в mxmlc, чтобы включить весь пакет.

2 голосов
/ 12 января 2011

Я сделал что-то похожее на ответ Дэниела, но вам даже не нужно объявлять переменные ... этого достаточно:

Block; Triangle; Pineapple;
2 голосов
/ 12 января 2011

Другие предлагали решения, но вот объяснение того, что происходит.

Оператор импорта на самом деле не включает код класса при компиляции. Он в основном переносит сигнатуру (ы) типа в область видимости, так что компилятор не преграждает.

С http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/statements.html#import

Если вы импортируете класс, но не используете его в своем скрипте, этот класс не экспортируется как часть SWF-файла. Это означает, что вы можете импортировать большие пакеты, не заботясь о размере SWF-файла; байт-код, связанный с классом, включается в SWF-файл, только если этот класс фактически используется. Одним из недостатков импорта классов, которые вам не нужны, является то, что вы увеличиваете вероятность конфликтов имен.

Представленные решения предоставляют методы для получения классов в SWF.

Edit:

Хорошо, я думаю, я лучше понимаю ваш первоначальный вопрос. Код класса должен прийти откуда-то. Он либо должен быть связан с помощью одного из представленных методов, либо вам нужно поместить классы в дочерние SWF-файлы и обновить логику, чтобы получить имя класса, загрузить соответствующий дочерний SWF-файл и получить определение класса из домен приложения SWF, который вы только что загрузили.

2 голосов
/ 12 января 2011

Я никогда не использовал ApplicationDomain.currentDomain.hasDefinition(className), вместо этого я использовал способ try catch, но похоже, что это лучший способ сделать это.так что спасибо за это.

в любом случае,

Я сталкивался (я думаю) с той же проблемой раньше.Проблема в том, что компилятор не компилирует все ваши my.factory.*; ресурсы.Что я сделал, так это создал фиктивный экземпляр каждого объекта, который мне потребуется.

privete function uncalledFunction():void{
  var s_01:Block;
  var s_02:Triangle;
  var s_03:Pineapple;
}

Этот «обман» сработал для меня, но мне интересно посмотреть, есть ли более элегантные решения.

0 голосов
/ 12 января 2011

Вот код, который я только что скинул. Я попробовал это на Временной шкале, и это работает. Это то, что вы хотите?

import flash.system.ApplicationDomain;

trace( makeInstance( "flash.display.Sprite" ) ); //[object Sprite]
trace( makeInstance( "flash.geom.Rectangle" ) ); //(x=0, y=0, w=0, h=0)
trace( makeInstance( "hi.there" ) ); //null

function makeInstance( className : String ) : *
{
    var MyClass:Class;
    var instance : * = null;

    if ( ! ApplicationDomain.currentDomain.hasDefinition( className ) ) return null;

    MyClass = getDefinitionByName( className ) as Class;
    return new MyClass();
}
...