ISerializable: назначить существующий объект на десериализацию
Наша задача довольно проста, у нас есть граф объектов, где каждый объект (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"));
}
Итак, есть идеи, как мы можем присвоить существующий объект десериализованному объекту?
С наилучшими пожеланиями, талм
2 ответа
Вы могли бы сделать это, создав прокси-объект, который реализует 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!");
}
}
Вы не можете сделать это прямо так.
Вместо того, чтобы сериализовать весь объект, но только одно поле, почему бы просто не передать идентификатор и выполнить поиск на клиенте и / или сервере? Если я правильно понимаю, экземпляр этого объекта уже существует на сервере. Не должно быть никаких причин, по которым вам нужно было бы пропустить удаленную версию этого объекта, чтобы снова найти тот же объект.
Если идентификатор уникален и хранится в коллекции где-то вместе с объектом, то для передачи идентификатора в виде строки или любого другого типа данных должно быть достаточно поиска в существующей коллекции объектов.