开发者

Passing Vector.<T> references as Object, casting causes a copy to be made

开发者 https://www.devze.com 2023-02-16 05:46 出处:网络
I\'d like to be able to pass Vectors around as references.Now, if a method takes a Vector.<Object>, then passing a Vector.<TRecord>, where TRecord inherits directly from Object does not wo

I'd like to be able to pass Vectors around as references. Now, if a method takes a Vector.<Object>, then passing a Vector.<TRecord>, where TRecord inherits directly from Object does not work. Where a method takes just plain Object; say vec: Object, then passing the Vector is possible. Once inside this method, an explicit cast at some stage is required to access vec as a Vector again. Unfortunately, a cast seems to make a copy, which means wrapping one up in multiple Flex ListCollectionViews is useless; each ListCollectionView will be pointing to a different Vector.

Using Arrays with ArrayCollection presents no such problem, but I lose out out the type safety, neatness (code should be clean enough to eat off of) and performance advantages of Vector.

Is there a way to cast them or pass them as references in a generic manner without copies being made along the way?

Note in this example, IRecord is an interface with {r/w id: int & name: String} properties, but it could be a class, say TRecord { id: int; name: String} or any other usable type.

protected function check(srcVec: Object): void
{
  if (!srcVec) {
    trace("srcVec is null!");
    return;
  }
  // srcVec = (@b347e21)
  trace(srcVec.length); // 4, as expected
  var refVec: Vector.<Object> = Vector.<Object>(sr开发者_如何学运维cVec);
  // refVec = (@bc781f1)
  trace(refVec.length); // 4, ok, but refVec has a different address than srcVec
  refVec.pop();
  trace(refVec.length); // 3 ok
  trace(srcVec.length); // 4 - A copy was clearly created!!!
}

protected function test(): void
{
  var vt1: Vector.<IRecord> = new Vector.<IRecord>;  // (@b347e21) - original Vector address
  var vt2: Vector.<Object> = Vector.<Object>(vt1);   // (@bbb57c1) - wrong
  var vt3: Vector.<Object> = vt1 as Vector.<Object>; // (@null)    - failure to cast
  var vt4: Object = vt1;                             // (@b347e21) - good
  for (var ix: int = 0; ix < 4; ix++)
    vt1.push(new TRecord);
  if (vt1) trace(vt1.length); // 4, as expected
  if (vt2) trace(vt2.length); // 0
  if (vt3) trace(vt3.length); // vt3 is null
  if (vt4) trace(vt4.length); // 4
  if (vt1) trace(Vector.<Object>(vt1).length); // 
  trace("calling check(vt1)");
  check(vt1);
}


This is not possible. If a type T is covariant with type U, then any container of T is not covariant with a container of type U. C# and Java did this with the built-in array types, and their designers wish they could go back and cut it out.

Consider, if this code was legal

var vt1: Vector.<IRecord> = new Vector.<IRecord>;  
var vt3: Vector.<Object> = vt1 as Vector.<Object>; 

Now we have a Vector.<Object>. But wait- if we have a container of Objects, then surely we can stick an Object in it- right?

vt3.push(new Object());

But wait- because it's actually an instance of Vector.<IRecord>, you can't do this, even though the contract of Vector.<Object> clearly says that you can insert Object. That's why this behaviour is explicitly not allowable.

Edit: Of course, your framework may allow for it to become a non-mutable reference to such, which is safe. But I have little experience with ActionScript and cannot verify that it actually does.

0

精彩评论

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