Почему удаляют (DictionaryInstance [ключ]); потерпеть поражение? - PullRequest
11 голосов
/ 08 октября 2011

Мое приложение использует словарь

protected _categoryToValueDict:Dictionary = new Dictionary();

для сопоставления чего-либо с чем-либо другим.

Теперь, в определенный момент в приложении мне нужно удалить определенный ключ из Dictionary.

Я реализовал этот простой метод:

    public function setCategoryNoValue( cat:TAModelCategory ):void {

        // delete( _categoryToValueDict[ cat ] );

        var old:Dictionary = _categoryToValueDict;

        _categoryToValueDict = new Dictionary();

        for ( var key:* in old ) {

            if ( key != cat ) {
                _categoryToValueDict[ key ] = old[ key ];
            }
        }

    }

Если я использую только [описание оператора delete ]

delete( _categoryToValueDict[ cat ] );

само приложение не выдает ошибок в обычном режиме.Но как только я сериализует его внешнюю структуру данных во внешний источник [в настоящее время SharedObject ], приложение не сможет десериализовать позже..

Если я использую вышеуказанную кодированную операцию итеративного ручного удаления , операция десериализации работает как положено и модель появляется в приложении.

Альтернатива должна быть идентичной.Разве они не должны?

Таким образом, мой вопрос: в чем разница между двумя альтернативами?

PS: Этот вопрос может быть связан с мой предыдущий .

ОБНОВЛЕНИЕ-1

Adobe объясняет на этой странице :


Чтобы сделать объект, на который ссылается myObject, подходящим для сборки мусора, вы должны удалить все ссылки на него.В этом случае вы должны изменить значение myObject и удалить ключ myObject из myMap, как показано в следующем коде:

myObject = null;
delete myMap[myObject];

Предполагается, что это опечатка.Разве это не должно читаться так:

delete myMap[myObject];
myObject = null;

Зачем передавать нулевой указатель в myMap в качестве ключа?

Ответы [ 2 ]

8 голосов
/ 03 ноября 2011

Ладно, я потратил примерно два часа на это, а это гораздо больше, чем я планировал потратить на это. Но я был заинтригован.

Я думаю, что вы, возможно, обнаружили законную ошибку в кодировке AMF в ActionScript (или в том, как класс Dictionary выделяется с помощью AMF). Эта ошибка влияет на все, что использует AMF, поэтому точно такую ​​же ошибку можно воспроизвести с помощью ByteArray, поэтому я собираюсь использовать ее в демонстрационных целях.

Рассмотрим следующий код:

        var d:Dictionary = new Dictionary(false);
        d["goodbye"] = "world";
        d["hello"] = "world";
        delete d["hello"]

        var ba:ByteArray = new ByteArray();
        ba.writeObject(d);

        var len:uint = ba.position; 
        ba.position = 0;
        for(var i:uint=0;i<len;i++) {
            trace(ba.readUnsignedByte().toString(16));
        }

Вывод будет:

11 05 00 06 0f 67 6f 6f 64 62 79 65 06 0b 77 6f 72 6c 64

А что если мы никогда не введем "hello" в качестве ключа:

        var d:Dictionary = new Dictionary(false);
        d["goodbye"] = "world";

        var ba:ByteArray = new ByteArray();
        ba.writeObject(d);

        var len:uint = ba.position; 
        ba.position = 0;
        for(var i:uint=0;i<len;i++) {
            trace(ba.readUnsignedByte().toString(16));
        }

Тогда вывод:

11 03 00 06 0f 67 6f 6f 64 62 79 65 06 0b 77 6f 72 6c 64

Обратите внимание, что длина абсолютно одинакова, однако они отличаются во втором байте.

Теперь давайте посмотрим на сериализацию, если я не удаляю "hello":

11 05 01 06 0b 68 65 6c 6c 6f 06 0b 77 6f 72 6c 64 06 0f 67 6f 6f 64 62 79 65 06 02

Обратите внимание, что 05 во втором байте такой же, как когда мы его удалили. Я думаю, что это указывает количество элементов в словаре. Я говорю «я думаю», потому что я довольно долго копался в документации по AMF0 / 3, пытаясь точно выяснить, что здесь происходит, потому что не похоже, что это должна быть сериализация для словаря, но она достаточно последовательна , но я не понимаю.

Так что я думаю, что именно поэтому вы нажимаете исключение (в частности, ошибку «Конец файла»), потому что он все еще думает, что в словаре должен быть еще один элемент, который он должен десериализовать.

Ваш альтернативный метод работает, потому что вы создаете новый Словарь и заполняете его ... Его "внутренний счетчик" только увеличивается, поэтому он работает как талисман.

Еще один момент, на который следует обратить внимание: если вы установите d["Hello"] = undefined, он не выдаст исключение, но элемент не будет удален из словаря. Ключ сериализуется со значением undefined в потоке AMF. Таким образом, результирующий поток байтов длиннее, чем если бы его никогда не было.

Использование Object, похоже, не демонстрирует такого же поведения. Мало того, что не выдает ошибку, сгенерированный байт-код больше соответствует документации AMF0 / 3, которую я мог найти в Adobe. И полученный «ключ» буквально отбрасывается из сериализации, как это было на самом деле никогда не было. Поэтому я не уверен, какой особый случай они используют для Dictionary (очевидно, недокументированный тип данных AMF3 0x11), но он не подходит для удаления из него элементов.

Мне кажется, это настоящая ошибка.

редактировать

Так что я немного покопался и обнаружил, что другие люди говорят о AMF-сериализации Dictionary.

0x11 : Dictionary Data Type
0x05 : Bit code: XXXX XXXY
     : If y == 0 then X is a reference to a previously encoded object in the stream
     : If y == 1 then X is the number of key/val pairs in the dictionary.

Так что, если в этом случае 5&1 == 1 и 5>>1 == 2, значит, в «плохой» сериализованной версии ожидается две пары ключ / вал.

0 голосов
/ 08 октября 2011

Правильный синтаксис для оператора delete выглядит следующим образом:

delete _categoryToValueDict[ cat ];

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

...