开发者

When extending Array, problems accessing members

开发者 https://www.devze.com 2023-03-18 15:29 出处:网络
I am currently working with some code that my co-worker wrote.Here is a simplified look at it: The People class:

I am currently working with some code that my co-worker wrote. Here is a simplified look at it:

The People class:

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

Which is basicly an Array of Persons:

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

This is basicly how my co-worker is using the code:

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();

Note: The he adds Person objects but he never looks at what is in the People Array except to print out the XML

Fast-forward (do people still know that this means?) to the present. I now need to look inside the People class and do something like this:

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

Unfortionatly this throws this error:

ReferenceError: Error #1069: Property 0 not found on model.People and there is no default va开发者_Go百科lue.
    at runner::Runner$/newUse()
    at ExtendsArray/start()
    at ExtendsArray/___ExtendsArray_Application1_initialize()
    at flash.events::EventDispatcher/dispatchEventFunction()

What should I do?

Edit, Aside: Extending Array is not my doing this is part of our old model. We are moving away from the old model because it is full of garbage like this. I just need to grab this stuff from the old model to convert it into the new model. I would like to tear this code out of our product but the cost of doing that is probably not warranted.


What should I do?

Use only class methods to access and set items in your "array", don't use Array-specific syntax. And/or make the class dynamic.


EDIT I think you can leave everything as is and avoid making your class dynamic by defining only one additional method for item access (if it's not there for some reason). Something like:

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

And I know that is not the way it's meant to be answered on stackoverwlow, but... I can't hold it. ))

Anything extends Array -- is a heresy. If I see that in production code, I'll immediatelly proceed to initiating a "purge the unclean" sequence.

Just try googling for the subject a little bit, and you will see, that almost no one has got alive and well from an activitiy like that.

The main rational reason why this abomination is not meant to exist (aside form it being a heresy) is that you can not use array access [], you can not instantiate it like a normal array with items and you can not set items through array syntax [] and be notified of the changes somewhere in your class. But it is an Array by the right of birth, so any of your fellow developers not familiar with the subject may try to use it like a normal Array, because it's quite natural. And then they'll probably post another question on stackoverflow.

So, if you are still limited to just using class methods, what's the point in extending anyway? Whay not use neat aggregation/composition or proxy ways?

It's amazing, but there's even an article on extending Array on adobe.com. What they do not mention there is that you are likely to start burning in hell right away.


Array.length is a getter: it returns an int. people.length() is the same as calling 3(). I don't know how it worked when you tested that.

It looks like you'd be better off implementing something like IList and have addItem push into a Vector.<Person>. That will guarantee that you only have Person objects.

You should probably should not be extending Array. If you want to extend anything, extend Proxy (You can even use the ProxyArray class example with a Vector.<Person>). Extending top level classes (with the exception of Object) is often an invitation for confusion.

If you really, really want to extend Array, you have to make the class dynamic -- you are arbitrarily assigning and removing properties.


This looks like it works:

var s:String = "";
for each(var per:Person in people){
    s += per.name + " ";    
}


The People class has to be scripted as public dynamic class since it is extending the Array class.

From this Adobe help article: A subclass of Array should use the dynamic attribute, just as the Array class does. Otherwise, your subclass will not function properly.


You used the "push" function which apparently created an associative array.

Associative arrays can not be called by index. They can also not be reversed or have their order changed.

You need to access them by using the for..in loop

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

The arr.length() function of an associative array will always be 0 and you saw that with your error.

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

精彩评论

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