#protocol-buffers #protobuf-net
#буферы протокола #protobuf-net
Вопрос:
Пожалуйста, обратите внимание на следующую простую программу (основанную на примере из вики protobuf-net project v1):
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ProtoBuf;
namespace HelloProtoBuf
{
[ProtoContract]
class Person
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
[ProtoContract]
class Address
{
[ProtoMember(1)]
public string Line1 { get; set; }
[ProtoMember(2)]
public string Line2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var person = new Person
{
Id = 12345,
Name = "Fred",
Address = new Address
{
Line1 = "Flat 1",
Line2 = "The Meadows"
}
};
var person2 = new Person
{
Id = 4553,
Name = "Nadya",
Address = person.Address
};
var persons = new List<Person> { person, person2 };
Debug.Assert(ReferenceEquals(persons[0].Address, persons[1].Address));
using (var file = File.Create("persons.bin"))
{
Serializer.Serialize(file, persons);
}
List<Person> persons2;
using (var file = File.OpenRead("persons.bin"))
{
persons2 = Serializer.Deserialize<List<Person>>(file);
}
Debug.Assert(ReferenceEquals(persons2[0].Address, persons2[1].Address));
}
}
}
Второе утверждение завершается ошибкой. Это ошибка в реализации protobuf-net или дело в том, что буферы протокола просто не поддерживают графы объектов с общими ссылками?
Спасибо.
Ответ №1:
буферы протокола сами по себе этого не поддерживают — так что нет, это не ошибка. Действительно, XmlSerializer
и DataContractSerializer
* сделали бы то же самое (и, вероятно, то же самое сделал бы JavaScriptSerializer
и JSON.NET ).
Тем не менее, это обычный запрос, поэтому он поддерживается в protobuf-net v2 (в основном: я обманываю). Просто измените его на:
[ProtoMember(3, AsReference=true)]
public Address Address { get; set; }
(и используйте DLL версии v2, которую я загружаю примерно через 5 минут, или создайте из кода)
*=предостережение: DataContractSerializer
поддерживает ссылки, но только если вы используете определенный конструктор; по умолчанию он отключен
Комментарии:
1. Возможно ли передать эту информацию через императивную модель (RuntimeTypeModel)? Проблема в том, что мои суррогаты приписываются DataContract / DataMember, чтобы избежать ссылки на protobuf-net. Спасибо.
2. @mark — да;
yourMetaType[3].AsReference = true;
, где3
номер поля (Order=3
на языке DCS)3. Итак, Марк, как эта сериализация графов работает за кулисами? Создаете ли вы скрытые идентификаторы int (например, суррогатный первичный ключ) для каждого ссылочного объекта, а затем восстанавливаете их во время загрузки?
4. @Lone да, именно это — только для отношений, отмеченных для этого использования, хотя
5. Потрясающе. Я собираюсь попробовать использовать его для быстрого и грязного сериализатора для Ludem Dare в эти выходные ( ludumdare.com/compo/rules ). Нужно много потрясающих инструментов ninja, подобных тому, который вы создали здесь!