.Net Binary Serialization - Как ограничить граф объектов? - PullRequest
1 голос
/ 18 марта 2009

У меня есть объект, который я хотел бы сериализовать и распределить между процессами настолько эффективно, насколько это возможно. Сам объект имеет ссылку на другой объект, например, так:

public class Foo
{
    // Unique Identifier:
    public int Id;
    public Bar Bar;
}

public class Bar
{
    // Unique Identifier:
    public int Id;
}

Дело в том, что я хочу только сериализовать Foo и запустить его по проводам. Я бы предпочел не включать Бар в то, что я отправляю по проводам, потому что это известно с другой стороны, и отправка его приведет к потере моей «пропускной способности».

То, о чем я думал, это:

  1. Во время сериализации я бы сериализовал ссылка на Бар (Foo.Bar) как int, содержащий: Bar.Id (который является уникальный идентификатор для экземпляров Bar)

  2. Только Foo будет отправлено через провод (содержащий вместо Бар собственности).

  3. Во время десериализации я бы получил INT, получить правильный бар из хранилище и положить его в Foo.Bar property.

Является ли это правильным подходом к задаче ограничения сериализации объекта графа? Есть ли лучший способ сделать это?

Ответы [ 3 ]

5 голосов
/ 18 марта 2009

Я не уверен, что я что-то здесь упускаю.

Просто используйте атрибут NonSerialized в поле, которое вы не хотите сериализовать.

Затем посмотрите на SerializationSurrogate , чтобы исправить ссылки при десериализации.

Я использую аналогичный подход для двоичной сериализации объектов LINQ2SQL.

UPDATE:

Лучшая идея (забыл об этом). Используйте OnDeserializedAttribute , это довольно просто в использовании.

Использование суррогатного подхода позволит вам вернуть другой экземпляр этого объекта, если он уже загружен в память. Я использую это (в IronScheme) для исправления ссылок на упакованные типы значений, которые могут существовать уже во время выполнения.

ОБНОВЛЕНИЕ 2:

Вы можете увидеть пример ISerializationSurrogate в середине следующего файла . (Заранее извиняюсь за безобразие).

3 голосов
/ 18 марта 2009

То, что вы описали, потребует ISerializable (настраиваемая сериализация) с обычной BinaryFormatter - однако, protobuf-net позволит вам упростить вещи (так что вам не нужно обрабатывать детали самостоятельно), обычно делая данные меньше в процессе:

[ProtoContract]
public class Foo : ISerializable
{
    // Unique Identifier:
    [ProtoMember(1)]
    public int Id;
    public Bar Bar;

    [ProtoMember(2)]
    private int? BarProxy {
        get {
           if(Bar == null) return null;
           return Bar.Id;
        }
        set {
           if(value == null) { Bar = null; }
           else { // fetch from repository
             Bar = new Bar(); 
             Bar.Id = value;
           }
        }
    }

    public Foo() { }

    void ISerializable.GetObjectData(SerializationInfo info,
           StreamingContext context) {
        Serializer.Serialize(info, this);
    }
    protected Foo(SerializationInfo info, StreamingContext context) {
        Serializer.Merge(info, this);
    }
}

public class Bar
{
    // Unique Identifier:
    public int Id;
}

Для более простых настроек:

Какой сериализатор вы используете?

  • с помощью BinaryFormatter вы помечаете поля, которые вам не нужны, как [NonSerialized]
  • с XmlSerializer, вы помечаете участников, которых вы не хотите, [XmlIgnore]
  • с DataContractSerializer, вы просто не помечаете их [DataContract]

Также - возможно, рассмотрим protobuf-net ; это имеет очень эффективный бинарный механизм; более чем BinaryFormatter

2 голосов
/ 18 марта 2009

Это звучит выполнимо, по сути, вы реализуете интерфейс ISerializable в Foo, который позволит вам контролировать способ сериализации Foo.

Затем вы реализуете соответствующий конструктор, и у вас будет доступ к состоянию, которое вы сохранили, и сможете вытащить идентификатор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...