Могу ли я использовать apply() с конструктором для передачи произвольного количества параметров

У меня есть функция, которая может принимать переменное число параметров с оператором отдыха.

Я хочу создать объект, передающий аргумент, собранный с помощью оператора rest, непосредственно в конструктор без создания объекта и вызова функции инициализации и без передачи всего массива, но параметров, которые я делаю с помощью функции apply ().

Является ли это возможным ? Использование приложения не работает.

public function myFunc(...arg) {

     // something link "new MyClass.apply(args)"
     return new MyClass();

}

person yuri    schedule 06.10.2010    source источник
comment
Мне было грустно видеть, что это невозможно сделать, так как я расширяю массив, чтобы сделать ConstantArray, удаляя все возможности добавления и удаления из него после того, как он был создан с помощью конструктора. Думаю, я все еще мог бы делать super.push() в каждом цикле for, :( не так хорошо, как делать super.apply(this, rest)   -  person WORMSS    schedule 18.10.2011


Ответы (4)


К сожалению нет. Невозможно заставить применить работу для конструктора. Обычно делается подготовка номера вызова на основе количества аргументов:

public function myFunc(...arg):Myclass {
  switch (arg.length) {
    case 0:return new MyClass();
    case 1:return new MyClass(arg[0]);
    case 2:return new MyClass(arg[0], arg[1]);

    //... etc

    case n:return new MyClass(arg[0], arg[1],..,arg[n]);
    default: throw new Error("too much arguments in myFunc");
  }
}
person Patrick    schedule 06.10.2010
comment
ой!! мои фабричные методы теперь начинают страдать - person yuri; 07.10.2010

Что ж, это привело меня к интересному долгому исследованию!

Я нашел этот аккуратный файл SWC, заполненный утилитами для имитации AS2 eval(): http://www.riaone.com/products/deval/index.html

И вот доказательство того, что то, что вы ищете, может действительно работать:

package tests {
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.utils.getQualifiedClassName;
    import r1.deval.D;

    public class RandomTests extends Sprite{

        public function RandomTests() {
            super();

            var test:BitmapData =   create(BitmapData, 100, 100, true, 0x00000000);
            trace(test);
        }


        public function create( pClass:Class, ... pArgs ):* {
            D.importClass(pClass);
            var fullQName:String =  getQualifiedClassName(pClass);
            var qNameSplit:Array =  fullQName.split("::");
            var className:String =  qNameSplit[1];
            fullQName =             qNameSplit.join(".");

            var statements:String =
            "import $0;\n" +
            "return new $1($2);";


            var args:Array =        [];
            for (var a:int = 0, aLen:int = pArgs.length; a < aLen; a++) {
                switch(pArgs[a].constructor) {
                    case String:
                        args[a] =   "\"" + pArgs[a] + "\"";
                        break;
                    default:
                        args[a] =   pArgs[a];
                        break;
                        //throw new Error("Unhandled type, please add it: " + pArgs[a].constructor);
                }
            }

            return D.eval(XString.gsub(statements,[fullQName, className, args.join(",")]));
        }
    }

}

Извините за биты зависимостей (например, мой класс XString для простых подзамен), но в теории это работает. Единственная проблема будет заключаться в передаче ссылок на объекты в качестве записей аргументов. Но опять же... класс r1.deval.D мог бы выдержать это... хм.

В любом случае, подумал, может быть, этим стоит поделиться.

person bigp    schedule 14.10.2010
comment
Я вспомнил этот ответ сегодня после некоторой проблемы, с которой я столкнулся при создании экземпляра для встроенных BitmapData. CS4, похоже, требует нового YourBitmap(-1, -1); конструктора, а в CS5 нет - new YourBitmap();. Неважно, но я начал думать... хм, может быть, SWC из r1.deval.D обманывает нас, заставляя думать, что он может обрабатывать ЛЮБЫЕ числа или параметры конструктора. Я имею в виду ... кто знает, может быть, они просто используют подход Патрика внутри (жестко запрограммированные параметры конструктора на основе длины аргументов). Очень хотелось бы извлечь их код, чтобы увидеть, как dEval смог это сделать. - person bigp; 17.11.2010
comment
D.eval будет обрабатывать только 20 параметров. Несмотря на сложность библиотеки, они делают то же самое, что и исходный вопрос. Это то, что делает CallExpr.newInstance(). Не стесняйтесь проверить это с классом, имеющим более 20 аргументов. - person grey; 02.02.2012

ну есть и это

public function myFunc(args:Object) {

   //then access various argumens
   return new MyClass(args.name, args.id, args.active)

}

и вызовите его через myFunc({id:33,name:'jo')

затем вы могли бы передать объект, или это слишком далеко от того, что вы ищете?

person Daniel    schedule 06.10.2010
comment
не так далеко, передача динамического объекта или класса VO была моим первым обходным путем. Мне было любопытно узнать, возможно ли это. - person yuri; 07.10.2010

Я тоже ищу ответ, но слишком грустно видеть, что ответ - нет....

Вот мой текущий (не очень хороший) способ делать такие вещи, надеюсь, что некоторые из вас заинтересуются:

// Foo.as
public class Foo {
    // construct
    public function Foo(... args):void {
        create.apply(this, args);
    }

    // this function do as a really construct function, tricky stuff
    function create(id:uint, name:String) {
        trace(id, name);
    }
}

// Bar.as
// for create this kind of class, just new it as usual
...
var foo:Foo = new Foo(123, "abc");
...
person quabug    schedule 03.11.2011