Protobuf-net Целостность ссылок на граф объектов - PullRequest
6 голосов
/ 06 июля 2011

В protobuf-net ver 2 есть аккуратная опция, которая называется [ProtoMember (2, AsReference = true)]. По большей части, это следующий вопрос:

Мне стало интересно, всегда ли поддерживается ссылочная целостность независимо от того, когда происходит сериализация / десериализация. protobuf-net уже делает это, когда вы используете опцию AsReference ?

Я собрал базовый пример кода для иллюстрации, а затем подумал: «Может быть, мне нужно позаимствовать некоторые идеи из мира ORM?» Должен ли я реализовывать карту личности? Должен ли я как-то сказать protobuf (через делегатов?) Вместо разрешения ссылок на / из значений внешнего ключа.

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

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

  • a => 1. разрешить ссылку на первичный ключ int, 2. сериализовать

  • b => 3. десериализация, 4. преобразование первичного ключа int в ссылку

Примечания / Ограничения:

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

  • граф объектов должен быть одинаковым независимо от того, когда объекты сериализуются. то есть A.ref = B (сериализация / десериализация). C.ref = B (сериализация / десериализация).

Пример для обсуждения:

using System;
using System.Collections.Generic;
using ProtoBuf;

namespace protobuf_question
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new A() { key = 1 };
            var b = new B() { A = a, key = 2 };
        }
    }

    [ProtoContract]
    public class A
    {
        [ProtoMember(1)]
        public int key { get; set; }
    }
    [ProtoContract]
    public class B
    {
        [ProtoMember(1)]
        public int key { get; set; }
        [ProtoMember(2,AsReference=true)]
        public A A { get; set; }  // a reference
    }
    [ProtoContract]
    public class IdentityMap<T,TKey>
    {        
        public static readonly IdentityMap<T,TKey> instance = new IdentityMap<T,TKey>();  // singleton
        private Dictionary<string, T> identitySpace { get; set; }
        public IEnumerable<string> GetIdentitySet (/* some criteria */)
        {            
            // used for serializing with reference safety between assemblies.
            throw new NotImplementedException();
        }
        public TKey GetKey(T reference)
        {
            // map object reference to identity map; return identity.
            throw new KeyNotFoundException();
        }
    }

}

1 Ответ

6 голосов
/ 06 июля 2011

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

Да, это возможно. При использовании AsReference=true он внутренне генерирует непрозрачный ключ, не связанный с чем-либо еще , и использует его на проводе; этот ключ основан на детерминированном характере потока. Все остается на 100% контрактной основе. Пока контракты совместимы, не имеет значения, относится ли он к одному типу, к одному и тому же процессу, к той же машине, к той же ОС и т. Д.

Единственное исключение из этого - при использовании опции DynamicType=true, когда он записывает метаданные типа в провод, но даже при том, что не обязательно должны быть фактическими данными типа - есть событие, на которое вы можете подписаться, если хотите предоставить что-то более детальное и контролируемое, чем по умолчанию (type.AssemblyQualifiedName). Если бы вы использовали DynamicType, это позволило бы вам прозрачно менять типы между реализациями. Конечно, если вы не используете DynamicType, то эта проблема вообще не существует.


Re ваша карта личности ... Мне неясно, мотивация там. Но, чтобы быть точным: существующий код не пытается идентифицировать каких-либо кандидатов в «первичный ключ» и сериализовать только те; он сериализует объект в первый раз, когда видит его (и изобретает ключ), в противном случае он просто записывает ключ, который он создал в прошлый раз.

...