ISerializable: назначить существующий объект на десериализацию - PullRequest
3 голосов
/ 09 июля 2010

наша задача довольно проста, у нас есть граф объектов, где каждый объект (IDItem) имеет уникальный идентификатор. Граф объектов существует два раза - на клиенте и на сервере.

Теперь мы передаем некоторые сериализуемые команды на сервер. Команда имеет в качестве полей некоторые из IDItems. IDItems реализуют интерфейс ISerializable и хранят свои идентификаторы только в SerializationInfo. Как:

// The method called when serializing a IDItem.
void GetObjectData(SerializationInfo info, StreamingContext context)
{
    // Instead of serializing this object, just save the ID
    info.AddValue("ID", this.GetID());
}

Проблема в том, как мы можем присвоить существующий объект экземпляру, который создает десериализатор? Очевидно, что-то похожее на следующее в конструкторе ISerializable не работает, потому что идентификатор «this» только для чтения:

//does not work   
protected IDItem(SerializationInfo info, StreamingContext context)
{
    this = GlobalObject.GetIDItem(info.GetString("ID"));
}

Так есть идеи, как мы можем присвоить существующий объект десериализованному объекту?

С наилучшими пожеланиями, thalm

Ответы [ 2 ]

5 голосов
/ 09 июля 2010

Вы могли бы сделать это, создав прокси-объект, который реализует IObjectReference и выполняет ложную десериализацию.

(Ваш прокси-объект должен существовать как на клиенте, так и на сервере, и я полагаю, что ваш тип управления версиями и т. Д. Также должен быть одинаковым на обоих.)

[Serializable]
public class Example : ISerializable
{
    // ...

    void ISerializable.GetObjectData(
        SerializationInfo info, StreamingContext context)
    {
        info.SetType(typeof(ExampleDeserializationProxy));
        info.AddValue("ID", this.GetID());
    }
}

// ...

[Serializable]
public class ExampleDeserializationProxy : IObjectReference, ISerializable
{
    private readonly int _id;

    private ExampleDeserializationProxy(
        SerializationInfo info, StreamingContext context)
    {
        _id = info.GetInt32("ID");
    }

    object IObjectReference.GetRealObject(StreamingContext context)
    {
        return GlobalObject.GetIDItem(_id);
    }

    void ISerializable.GetObjectData(
        SerializationInfo info, StreamingContext context)
    {
        throw new NotSupportedException("Don't serialize me!");
    }
}
1 голос
/ 09 июля 2010

Вы не можете сделать это прямо так.

Вместо того, чтобы сериализовать весь объект, но только одно поле, почему бы просто не отправить его по идентификатору и не выполнить поиск на клиенте и / или сервере? Если я правильно понимаю, экземпляр этого объекта уже существует на сервере. Не должно быть никаких причин, по которым вам нужно было бы пропустить раздетую версию этого объекта, чтобы снова найти тот же объект.

Если идентификатор является уникальным и хранится в коллекции где-то вместе с объектом, то для передачи идентификатора в виде строки или любого другого типа данных должно быть достаточно поиска в существующей коллекции объектов.

...