ActionScript 3
Utilisation de la classe proxy
Recherche…
Introduction
Tout d'abord, je dois dire. Il y a une raison pour laquelle ce truc, malgré son utilité apparente, n'est pas suffisamment mis en évidence sur Internet.
Vous ne pouvez pas l' utiliser pour regarder une propriété aléatoire d'une classe / instance aléatoire. Vous ne pouvez utiliser cette technique qu'en sous- classant la classe Proxy .
Certaines opérations n'attendent pas d'exceptions, vous devez donc comprendre complètement ce que vous faites et pourquoi vous le faites, et votre code doit être absolument propre et sans erreur.
la mise en oeuvre
L'autre chose à propos de la classe Proxy, et pourquoi elle n'est pas si populaire, est qu'il est plutôt difficile d'imaginer un problème qui nécessite une classe dynamique avec un accès contrôlable à ses propriétés et méthodes dynamiques. Chaque fois que j'ai essayé d'utiliser Proxy, j'ai fini par recourir à autre chose, plus simple et plus contrôlable.
Cependant, ne nous décourageons pas. J'aime l'idée d'adresser les derniers éléments du tableau par les indices [-1], [-2], etc. dans Python . Ce n'est peut-être pas un gros exploit, mais ça fait du bien d'utiliser ça plutôt que de longs et maladroits someArray [someArray.length - 1] . Voyons ce que nous pouvons faire à ce sujet.
package
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
/**
* Pyaray the Tentacled Whisperer of Impossible Secrets.
*/
dynamic public class PyArray extends Proxy
{
private var data:Array;
public function PyArray(...args:Array)
{
if (args.length == 0)
{
data = new Array;
}
else if ((args.length == 1) && (args[0] is Array))
{
data = args[0];
}
else
{
data = args;
}
}
// This is a getter proxy to all the available Array
// elements and properties and, sometimes, methods.
override flash_proxy function getProperty(name:*):*
{
var anIndex:int = name;
// Handle the int indices of the Array elements.
if (anIndex == name)
{
// Handle the -1, -2, etc indexing.
if (anIndex < 0) anIndex += data.length;
if (anIndex >= data.length) return null;
if (anIndex < 0) return null;
return data[anIndex];
}
// Handle the existing public Array properties.
if (data.hasOwnProperty(name)) return data[name];
// Handle the Array methods addressed via ["member"] access.
try
{
if (data[name] is Function) return data[name];
else throw new Error;
}
catch (fail:Error)
{
trace("[PyArray] is unable to resolve property \"" + name + "\".");
}
return null;
}
// This will set either elements, or settable properties.
override flash_proxy function setProperty(name:*, value:*):void
{
var anIndex:int = name;
// Handle the int indices of the Array elements.
if (anIndex == name)
{
// Handle the -1, -2, etc indexing.
if (anIndex < 0) anIndex += data.length;
// In case the element index is out of range,
// the PyArray will extend its data Array.
// if (anIndex >= data.length) return;
if (anIndex < 0) return;
data[anIndex] = value;
return;
}
// Handle the existing (or dynamic) public Array properties.
try
{
data[name] = value;
}
catch (fail:Error)
{
trace("[PyArray] is unable to set property \"" + name + "\".");
}
return;
}
// This allows to delete PyArray elements with "delete" operator.
override flash_proxy function deleteProperty(name:*):Boolean
{
var anIndex:int = name;
// Handle the int indices of the Array elements.
if (anIndex == name)
{
// Handle the -1, -2, etc indexing.
if (anIndex < 0) anIndex += data.length;
if (anIndex >= data.length) return false;
if (anIndex < 0) return false;
data.splice(anIndex, 1);
return true;
}
// Handle the dynamic public Array properties.
try
{
delete data[name];
return true;
}
catch (fail:Error)
{
trace("[PyArray] is unable to delete the \"" + name + "\" property.");
}
return false;
}
// This proxies any attempt to call a method on PyArray directly to data Array, thus
// all Array methods (including "toString" method called through trace) are available.
override flash_proxy function callProperty(name:*, ...rest):*
{
try
{
return (data[name] as Function).apply(data, rest);
}
catch (fail:Error)
{
trace("[PyArray] is unable to resolve method \"" + name + "\".");
return null;
}
}
// This allows PyArray to handle for..in and for..each..in loops.
// The initial call starts with zero, so we need to do this +1 -1 magic
// in order for enumeration to work correctly. I'm not happy with this either.
override flash_proxy function nextNameIndex(index:int):int
{
if (index >= data.length) return 0;
else return index + 1;
}
// This method handles the for..in loop.
override flash_proxy function nextName(index:int):String
{
return (index - 1).toString();
}
// This method handles the for..each..in loop.
override flash_proxy function nextValue(index:int):*
{
return data[index - 1];
}
}
}
Usage
package
{
import flash.display.Sprite;
/**
* Daemonette of Slaanesh.
*
* It is minor female demon, vaguely human-like, but with crab-like pincers instead of hands.
* She wears a rather indecent skimpy leather bikini, moves quickly and casts deadly spells!
*/
public class Slaanesh extends Sprite
{
public function Slaanesh()
{
// Lets initialize the PyArray.
var PA:PyArray = new PyArray(1,2,3,4,5,4,3,2,1,"Foo");
// Basic check: get the last element.
trace(PA[-1]);
// output:
// Foo
// This will map to the 0-based third element.
trace(PA[2.0]);
// output:
// 3
// This should not get us anywhere.
trace(PA[2.1]);
// output:
// [PyArray] is unable to resolve property "2.1".
// null
// This should return the length of the data Array.
trace(PA["length"]);
// output:
// 10
// This should return the length of the data Array.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.length);
// output:
// 10
// This will map to indexOf method of data Array via getProperty method.
trace(PA["indexOf"]);
// output:
// function Function() {}
// This will map to indexOf method of data Array via getProperty method.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.indexOf);
// output:
// function Function() {}
// This is a try to access a non-existent property.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.P124);
// output:
// [PyArray] is unable to resolve property "P124".
// null
// This is a try to call a non-existent method via callProperty method.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.P124());
// output:
// [PyArray] is unable to resolve method "P124".
// null
// Basic check: calling a proxied method via callProperty method.
trace(PA.indexOf(5));
// output:
// 4
// An attempt to replace an Array method with a random value.
// This will not compile unless PyArray class is marked "dynamic".
PA.indexOf = 123;
// output:
// [PyArray] is unable to set property "indexOf".
// An attempt to assign a random value to a random property.
// It will succees because Array, as a dynamic class, allows so.
// This will not compile unless PyArray class is marked "dynamic".
PA.indexOfz = 123;
trace(PA.indexOfz);
// output:
// 123
// An attempt to assign an Array element via negative indexing.
// This trace works fine because toString method is also proxied.
PA[-3] = "Hello";
trace(PA);
// output:
// 1,2,3,4,5,4,3,Hello,1,Foo
// An attempt to delete Array elements via normal and negative indexing.
// This operation is mapped via deleteProperty method.
delete PA[-4]; // deletes "3" before "Hello"
delete PA[0]; // deletes "1" at the start.
trace(PA);
// output:
// 2,3,4,5,4,Hello,1,Foo
// An attempt to delete a non-dynamic method reference.
// There's no error output, AS3 must be handling this internally.
delete PA.indexOf;
trace(PA.indexOf);
// output:
// function Function() {}
// An attempt to set an element out of index range.
PA[10] = "123abc";
trace(PA);
// output:
// 2,3,4,5,4,Hello,1,Foo,,,123abc
var aText:String;
// This is a test of for..in loop, Array elements are
// enumerated via nextName and nextNameIndex methods.
aText = ""
for (var aKey:String in PA)
aText += aKey + ":" + PA[aKey] + " ";
trace(aText);
// output:
// 0:2 1:3 2:4 3:5 4:4 5:Hello 6:1 7:Foo 8:undefined 9:undefined 10:123abc
// This is a test of for..each..in loop, Array elements are
// enumerated via nextValue and nextNameIndex methods.
aText = "";
for each (var aValue:* in PA)
aText += aValue + " ";
trace(aText);
// output:
// 2 3 4 5 4 Hello 1 Foo undefined undefined 123abc
}
}
}