При расширении массива проблемы с доступом к членам - PullRequest
0 голосов
/ 08 июля 2011

В настоящее время я работаю с кодом, написанным моим коллегой.Вот упрощенный взгляд на это:

Класс People:

package model{
    public class People extends Array{ // NOTE: it is not dynamic

        public function toXML():XML {
            var out:XML = <people/>;
            for each(var per:Person in this){
                out.appendChild(per.toXML());
            }
            return out;
        }
    }
}

, который в основном является массивом людей:

package model{
    public class Person {

        public var name:String;
        public var phoneNumber:String;

        public function Person(name:String, phoneNumber:String){
            this.name = name;
            this.phoneNumber = phoneNumber;
        }

        public function toXML():XML {
            var xml:XML = <person/>;
            xml.@name = name;
            xml.@phone = phoneNumber;
            return xml;
        }
    }
}

Это в основном то, как мой сотрудник-работник использует код:

var people:People = new People();
people.push(new Person("Jake", "902 825-4444"));
people.push(new Person("Bob", "514 444-3333"));
return people.toXML().toXMLString();

Примечание: он добавляет объекты Person, но он никогда не смотрит на то, что находится в массиве людей, за исключением распечатки XML

Перемотка вперед (люди все еще знают, что это значит?) В настоящее время.Теперь мне нужно заглянуть внутрь класса People и сделать что-то вроде этого:

var people:People = ... init and fill with Person objects
for(var i:int=0; i<people.length(); i++){
    doSomething(people[i]); // <-- Error thrown here.
}

Вынужденно выдает эту ошибку:

ReferenceError: Error #1069: Property 0 not found on model.People and there is no default value.
    at runner::Runner$/newUse()
    at ExtendsArray/start()
    at ExtendsArray/___ExtendsArray_Application1_initialize()
    at flash.events::EventDispatcher/dispatchEventFunction()

Что мне делать?

Edit, Aside: Расширение массива - не моя работа, это часть нашей старой модели.Мы удаляемся от старой модели, потому что она полна такого мусора.Мне просто нужно взять этот материал из старой модели, чтобы преобразовать его в новую модель.Я хотел бы вырвать этот код из нашего продукта, но затраты на это, вероятно, не гарантированы.

Ответы [ 5 ]

2 голосов
/ 08 июля 2011

Что мне делать?

Используйте только методы класса для доступа и установки элементов в вашем «массиве», не используйте специфичный для Array синтаксис. И / или сделать класс динамическим.

<Ч />

РЕДАКТИРОВАТЬ Я думаю, что вы можете оставить все как есть и не делать свой класс динамическим , определяя только один дополнительный метод для доступа к элементу (если его по какой-то причине нет). Что-то вроде:

public functon getItem(index:uint):*
{
    if (index >= length) {
        return null;
    }
    return this.slice(index, index+1)[0]; 
    // this creates a redundant array on the fly, sorry.
}

// usage:

var people:People = ... init and fill with Person objects
for(var i:int=0; i<people.length(); i++){
    doSomething(people.getItem(i));
}
<Ч />

И я знаю, что это не тот способ, которым нужно отвечать на stackoverwlow, но ... я не могу это удержать. ))

Anything extends Array - это ересь. Если я увижу это в рабочем коде, я немедленно приступлю к инициации последовательности «очистить нечистую».

Просто попробуйте немного погуглить по этому предмету, и вы увидите, что от такой деятельности почти никто не выжил.

Основная рациональная причина, по которой эта мерзость не предназначена для существования (кроме ереси), заключается в том, что вы не можете использовать доступ к массиву [], вы не можете создать его экземпляр как обычный массив с элементами, и вы не можете установить элементы с помощью синтаксиса массива [] и получать уведомления об изменениях где-то в вашем классе. Но это является массивом по праву рождения, поэтому любой из ваших коллег-разработчиков, не знакомый с предметом, может попытаться использовать его как обычный массив, потому что это вполне естественно. И тогда они, вероятно, опубликуют еще один вопрос по stackoverflow.

Итак, если вы все еще ограничены использованием только методов класса, какой смысл в любом случае расширяться? Почему бы не использовать аккуратные способы агрегации / композиции или прокси?

Удивительно, но даже на сайте есть статья о расширении массива . Они не упоминают, что вы, вероятно, сразу же начнете гореть в аду.

2 голосов
/ 08 июля 2011

Array.length является геттером: он возвращает int. people.length() - это то же самое, что 3(). Я не знаю, как это работало, когда ты это проверял.

Похоже, вам лучше реализовать что-то вроде IList и получить addItem толчок в Vector.<Person>. Это гарантирует, что у вас есть только объекты Person.

Вы, вероятно, не должны расширять Array. Если вы хотите расширить что-либо, расширьте Proxy (Вы можете даже использовать пример класса ProxyArray с Vector.<Person>). Расширение классов верхнего уровня (за исключением Object) часто вызывает путаницу.

Если вы действительно, действительно хотите расширить Array, вы должны сделать класс динамическим - вы произвольно назначаете и удаляете свойства.

0 голосов
/ 08 июля 2011

Вы использовали функцию «push», которая очевидно создала ассоциативный массив.

Ассоциативные массивы нельзя вызывать по индексу. Их также нельзя отменить или изменить их порядок.

Вам нужно получить к ним доступ, используя цикл for..in

for (var key:String in people) {
  trace("person : " + (people[key] as person).name);
}

// or as you found out the for each.. in
for each(var person:Person in people){
  trace("person : " + person.name);
}

Функция arr.length () ассоциативного массива всегда будет 0, и вы видели это с вашей ошибкой.

//Try this example you will see how an array can act like an array as we know it and an object.
var a:Array = [];
a[0] = true;
a.push(true);
a.push(true);
a["foo"] = true;
a.push(true);
a.push(true);
a.bar = true;


trace("for loop\n");
for(var i:int = 0, ilen:int = a.length ; i < ilen ; i++){
    trace(i,a[int(i)]);
}

trace("\nfor...in loop\n");
for(var key:String in a){
    trace(key,a[key]);
}
0 голосов
/ 08 июля 2011

Класс People должен быть записан как public dynamic class, поскольку он расширяет класс Array.

Из этой справочной статьи Adobe : подкласс Array должен использовать динамический атрибут, так же как и класс Array. В противном случае ваш подкласс не будет функционировать должным образом.

0 голосов
/ 08 июля 2011

Похоже, это работает:

var s:String = "";
for each(var per:Person in people){
    s += per.name + " ";    
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...