ProtoBuf-net сериализация IEnumerable ‹T›

Я пытаюсь использовать ProtoBuf-NET в своем проекте (в основном это проект Silverlight 4).

У меня проблемы с сериализацией моих коллекций моделей, все они определены следующим образом:

private List<T> _itemsSet;
public IEnumerable<T> TSet
{
    get {return _itemsSet;}
    set {_itemsSet = value == null ? new List<T>() : new List<T>(value);}
}
public void AddT(T item)
{
    //Do my logic here
    _itemsSet.Add(item);
}

Обновление: сначала я не могу сериализовать его - No serializer defined for type: System.Collections.Generic.IEnumerable1 [MyType] `. Во-вторых, я думаю, что не смогу удалить его на основе ручного анализа и анализа исходного кода protobuf-net.

  1. Есть ли способ расширить protobuf-net для предоставления делегата внешнему методу Add в атрибуте ProtoMemeber?
  2. Почему использование ProtoMember(1, OverwriteList=true) не работает? Разве это не предполагает перезапись коллекции и не нужно заботиться о Add<T>() методе? Почему он просто не пытается установить для этого свойства значение T [] или List<T> или какой-либо другой набор, который можно присвоить IEnumerable<T>?
  3. Есть ли способ предоставить настраиваемый механизм отражения для работы с частными полями в Silverlight, например: реализация: public interface IReflectable{ object GetValue(FieldInfo field); void SetValue(FieldInfo field, object value); } для работы с частными полями. Я использовал такой подход для работы с приватными полями в Db4o: http://community.versant.com/Forums/tabid/98/aft/10881/Default.aspx.
  4. Какие у меня есть возможности, кроме создания унаследованных MyTypeCollection<T> : Collection<T>?

person Alex Burtsev    schedule 17.10.2011    source источник
comment
Вы пробовали реализовать ISerializable в содержащем классе?   -  person Jonathan Dickinson    schedule 17.10.2011
comment
Я приписал это (универсальный тип аргумента IEnumerable) с помощью ProtoContract   -  person Alex Burtsev    schedule 17.10.2011
comment
Вы также можете найти Суррогаты полезны.   -  person Jonathan Dickinson    schedule 17.10.2011


Ответы (2)


  1. нет в настоящее время, нет; открытый тип должен иметь (как минимум) Add метод. Хотя у меня нет возражений против исследования возможности Add вне самого объекта, это сложно, поскольку вы затем смотрите на другой «первичный» объект (последовательность против контейнера). Тем не мение; если ваш родительский объект реализовал IEnumerable<T> (возвращает _itemsSet.GetEnumerator() и т. д.), он найдет Add автоматически

  2. Я не вижу здесь контекста; тем не менее, я подозреваю, что без Add он все равно не будет считать его списком в первую очередь. Однако я вижу, как вы поступаете с этим, и, возможно, это может послужить основанием для аргументации: «Я могу использовать List<T> здесь)

  3. Честно говоря, я не исследовал этого; итак: нет

  4. Тип, представленный в свойстве, должен, как минимум: реализовывать IEnumerable (хотя было бы предпочтительнее IEnumerable<T>) и предоставлять Add(T) метод. Это не обязательно должно быть Collection<T> / List<T> / и т.д. - просто: он должен (в настоящее время) иметь какой-то механизм для добавления. IList<T> было бы прагматичным вариантом, но я так понимаю, что это не совсем то, что вам нужно.

Джонатан прав в том, что суррогат внешнего класса (того, что имеет _itemsSet, TSet и AddT) также может быть вариантом.

Если внешний класс только существует, чтобы иметь коллекцию и метод добавления, то простое добавление : IEnumerable<T> и переименование AddT в Add, вероятно, заставит его работать.

person Marc Gravell    schedule 17.10.2011
comment
Как насчет моей проблемы сериализации IEnumerableT? Я запустил свой код в режиме отладки с последним исходным кодом protobuf-net, а Collection | IEnumerable ‹T› обрабатывающий код в ValueMember.cs: TryGetCoreSerializer СТРОКА: 330 Итак, я получаю исключение в строке ValueMember.cs: 262. - person Alex Burtsev; 17.10.2011
comment
@Alex сам по себе, IEnumerable<T> не может быть сериализован, так как он не может надежно десериализовать его. В лучшем случае я могу дать вам более точное сообщение об ошибке! Он может (я очень, очень надеюсь) обрабатывать Collection, но для Add вещей он должен иметь некоторый API для открытого типа. - person Marc Gravell; 17.10.2011
comment
Планируете ли вы продолжить работу над protobuf-net и расширить его? Что такое статус проекта? Я надеялся использовать его в реальном проекте, но в текущем состоянии он непригоден для меня, подумал, что это все же лучше, чем писать собственное решение с нуля. - person Alex Burtsev; 17.10.2011
comment
@Alex находится в активной разработке и использовании. Повторное расширение - сначала мне нужно четко понять проблему, для чего более полный пример мне очень поможет. - person Marc Gravell; 17.10.2011
comment
Все мои модели выставляют коллекции с помощью IEnumerable ‹T›. Это просто означает, что доступ к базовой коллекции можно получить только через этот ограниченный интерфейс. Хотя IEnumerable ‹T› не сериализуем, почему бы вам просто не десериализовать содержимое в список ‹T›. Это реализует IEnumerable ‹T›, но у вас есть полный контроль над содержимым. Я не хочу изменять семантику всех моих моделей представления просто для целей сериализации, и поэтому это неутешительный результат. - person G-Mac; 21.08.2012
comment
@ G-Mac да, но вы слишком упрощаете. В общем случае это более сложно ... например, предположим, что выполняется десериализация и обнаруживается, что свойство не равно нулю; что ему тогда делать? ему нужно добавить данные, но изменение реализации не идеально и ломается так же, как и исправления сценариев. Тем не мение! Вы можете достаточно легко добавить свойство прокладки, которое будет иметь любые правила, которые вы хотите. То, что вы описываете (автоматический вывод через List<T>) полностью поддерживается для IList<T> свойств, потому что он может * использовать существующий .Add, если обнаружит, что это не null. - person Marc Gravell; 21.08.2012
comment
Я чувствую, что если я сериализую объект с помощью свойства IEnumerable, есть четкая семантика в отношении того, как это используется. Если у меня есть какое-то базовое поведение в реализации поддержки, которое должно быть точно восстановлено для поведения, а не только для данных, тогда почему я в первую очередь сериализую объект? Возможно, у меня узкое представление о том, для каких структур люди сериализуют данные, потому что с тем, как я использую сериализацию, меня в конечном итоге не волнует, что поддерживает свойство (позже я не буду понижать значение базового объекта). Спасибо за работу над этим, я проверю предложение прокладки. - person G-Mac; 21.08.2012
comment
@ G-Mac Я вам вот что скажу: позже я проведу обзор других сопоставимых сериализаторов - XmlSerializer, DataContractSerializer, JSON.NET и JavaScriptSerializer. Если кто-то из них поддержит это, я посмотрю, что я могу сделать ... - person Marc Gravell; 21.08.2012
comment
@ G-Mac я проверил; похоже, что DataContractSerializer и JavaScriptSerializer поддерживают это использование, поэтому я добавил его в список для реализации - person Marc Gravell; 22.08.2012
comment
Фантастика! Спасибо, Марк. Я с нетерпением жду возможности вернуться к этому. - person G-Mac; 23.08.2012
comment
Я снова работаю над этим и искал возможность включить protobuf в наш проект. Используя последнюю версию на nuget, я все еще получаю сообщение об ошибке Нет сериализатора, определенного для типа: System.Collections.Generic.IEnumerable`1. Я вижу, что в r584 вы добавили образец, ссылающийся на сериализацию голых перечислимых элементов, но похоже, что он когда-либо был реализован. Можешь подтвердить? - person G-Mac; 14.04.2013
comment
@ G-Mac да, я заметил это в пятницу. Каков именно сценарий? Проблемный случай - сериализация Foo: IEnumerable-of-T, но без добавления - это ваш пример? Или у вас другой сценарий? - person Marc Gravell; 14.04.2013
comment
@MarcGravell да. Я предоставляю свойства своих моделей как IEnumerable ‹T›, и я хочу кэшировать их как копии посредством сериализации. Сейчас мы используем BinaryFormatter, но в качестве оптимизации я ищу более компактную и быструю альтернативу. Мне удалось заставить некоторые из моих моделей работать с сериализатором protobuf-net, но мне потребовалось изменить все мои свойства с IEnumerable ‹T› на IList ‹T›. Когда вы берете зависимость от IEnumerable ‹T›, вы просто абстрагируете семантику доступа к этим данным. Неважно, стоит ли за ним массив, List ‹T› или что-то еще. - person G-Mac; 14.04.2013
comment
@ G-Mac, если вы планируете десериализовать его обратно как Foo, это имеет значение :) однако вы можете использовать SerializeItems / DeserializeItems в этом сценарии, не так ли? - person Marc Gravell; 14.04.2013
comment
@MarcGravell Я обдумал это, чтобы попытаться лучше объяснить. gist.github.com/gmcelhanon/5391894 - person G-Mac; 16.04.2013
comment
@ G-Mac Я не могу винить ваш аргумент; Я могу поддержать этот сценарий - он будет работать при следующем развертывании - person Marc Gravell; 16.04.2013
comment
@MarcGravell, что насчет, скажем, IReadOnlyList<T>? Я написал (изменяемые) классы, реализующие этот интерфейс, и, конечно, можно обернуть List<T> в объект, реализующий IReadOnlyList<T>, поэтому кажется, что десериализация в поле IReadOnlyList<T> тоже должна быть возможна. - person Qwertie; 25.08.2013
comment
Конечно, есть два способа обработки поля IReadOnlyList<T> или IEnumerable<T>: (1) иногда нам все равно, каков фактический тип. Мы можем использовать поле repeated и десериализовать его до любого доступного типа, такого как List<T> (2), иногда мы хотим сохранить исходный тип коллекции при десериализации и, возможно, даже обработать саму коллекцию (в отличие от ее элементов) AsReference. (Обратите внимание: пользователь может выбрать (1) или (2) для каждого поля или типа за типом.) Я чувствую, что protobuf-net не поддерживает второй сценарий, поправьте меня, если я ошибаюсь? - person Qwertie; 25.08.2013
comment
@Qwertie в теории, нормально: но ему нужен код для распознавания шаблона, его реализации, тестирования и регрессионного тестирования существующих поддерживаемых сценариев. все выполнимо, если есть реальная необходимость - person Marc Gravell; 25.08.2013
comment
Коллекции @Qwertie в значительной степени являются деталью реализации - на данный момент никакая информация о контейнере не хранится. - person Marc Gravell; 25.08.2013

Я пытался срезать углы и повторно использовать мою модель в качестве контракта сообщения, но на самом деле это неверный подход. Лучше всего создать специализированные классы и конвертер DTO для вашей модели, в любом случае хорошо отделить вашу модель от сообщений.

Однако я должен критиковать Марка за добавление атрибутов ProtoContract и ProtoMemeber, которые побуждают пользователей повторно использовать свою модель путем ее атрибуции.

person Alex Burtsev    schedule 17.10.2011
comment
Критика может быть хорошей вещью, но я заинтригован тем, что вы хотите, чтобы я сделал вместо этого (и подумайте здесь также об атрибутах XmlSerializer, атрибутах DataContractSerializer и т. Д.). Так получилось, что в v2 все можно делать без атрибутов, если вы предпочитаете. И я с радостью предложу больше информации, если увижу сценарий, достаточно полный для запуска (на данный момент у меня есть только фрагмент одного класса, что не позволяет легко понять контекст и предложить ввод) - person Marc Gravell; 17.10.2011