Объект, не созданный в OnDeserialized [duplicate]

x = y = 5 эквивалентен x = (y = 5), поскольку работает оператор присваивания «группа» справа налево. Значение: присвойте 5 на y, оставив номер 5; а затем назначьте это значение 5 в x.

Это не то же самое, что (x = y) = 5, что не работает! Значение: присвойте значение y x, оставив значение y; а затем назначьте 5, umm ..., что именно?

Когда вы смешиваете разные типы операторов присваивания, <- привязывается сильнее, чем =. Таким образом, x = y <- 5 интерпретируется как x = (y <- 5), что имеет смысл.

К сожалению, x <- y = 5 интерпретируется как (x <- y) = 5, что не работает!

См. ?Syntax и ?assignOps для правил приоритета (привязки) и группировки.

5
задан Matt 30 August 2014 в 16:51
поделиться

1 ответ

Предполагаю, что вы используете BinaryFormatter .

BinaryFormatter - сериализатор графа. Вместо того, чтобы объекты хранятся в чистом дереве, им присваиваются временные идентификаторы объектов и хранятся в том виде, в котором они встречаются. Таким образом, когда объект десериализуется, не гарантируется, что все ссылочные объекты были ранее десериализованы. Таким образом, записи в вашем forwardMap еще не заполнены.

Обычным обходным путем является добавление логики IDeserializationCallback в ваш класс и создание ваших inverseMap и inverseInstance после того, как все было десериализовано в OnDeserialization . Но Dictionary<TKey, TValue> также реализует IDeserializationCallback , что вводит дополнительную проблему секвенсирования: она не гарантируется, что она была вызвана до вашего. В этой теме Microsoft пишет :

Объекты реконструируются изнутри, а вызывающие методы во время десериализации могут иметь нежелательные побочные эффекты, поскольку вызванные методы могут ссылаться на ссылки на объекты, которые не были десериализованы к моменту вызова. Если десериализованный класс реализует IDeserializationCallback, метод OnSerialization будет автоматически вызываться, когда весь объектный граф будет десериализован. На этом этапе все дочерние объекты, на которые делается ссылка, были полностью восстановлены. Хэш-таблица является типичным примером класса, который трудно десериализовать без использования прослушивателя событий, описанного выше. Легко получить пары ключ / значение во время десериализации, но добавление этих объектов обратно в хеш-таблицу может вызвать проблемы, поскольку нет гарантии, что классы, полученные из хеш-таблицы, были десериализованы. Поэтому методы вызова в хеш-таблице на этом этапе нецелесообразны.

Таким образом, есть несколько вещей, которые вы могли бы сделать:

  1. Вместо того, чтобы хранить Dictionary<TKey,TValue>, сохраните массив из KeyValuePair<TKey,TValue>. Это имеет преимущество, заключающееся в том, что ваши двоичные данные проще, но вам требуется выделить массив в вашем GetObjectData() методе.
  2. Или следовать рекомендациям в справочном источнике словаря :
    // It might be necessary to call OnDeserialization from a container if the container object also implements
    // OnDeserialization. However, remoting will call OnDeserialization again.
    // We can return immediately if this function is called twice. 
    // Note we set remove the serialization info from the table at the end of this method.
    
    Т.е. в своем обратном вызове вызовите метод OnDeserialization вашего вложенного словаря перед его использованием:
    public partial class BidirectionalDictionary<TKey, TValue> : IDeserializationCallback
    {
        public void OnDeserialization(object sender)
        {
            this.forwardMap.OnDeserialization(sender);
            foreach (KeyValuePair<TKey, TValue> entry in forwardMap)
            {
                this.inverseMap.Add(entry.Value, entry.Key);
            }
            // inverseInstance will no longer be able to be read-only sicne it is being allocated in a post-deserialization callback.
            this.inverseInstance = new BidirectionalDictionary<TValue, TKey>(this);
        }
    
    (вместо этого вы можете сделать это в методе [OnDeserialied] .)

Кстати, это сообщение в блоге утверждает, что безопасно вызывать метод OnDeserialization для HashTable из конструктора десериализации содержащего класс , а не позже OnDeserialization, чтобы вы могли попробовать.

7
ответ дан dbc 26 August 2018 в 14:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: