列表的 Protobuf.net 对象图序列化
Posted
技术标签:
【中文标题】列表的 Protobuf.net 对象图序列化【英文标题】:Protobuf.net object graph serialization for lists 【发布时间】:2011-09-08 12:02:29 【问题描述】:我了解使用 protobuf.net 的列表不支持 AsReference,因此我尝试了解决此限制的方法。我创建了一个名为 SuperList 的自定义列表,其中包含包装在 SuperListItem 类型的对象中的项目,如下所示:
[ProtoContract]
public class SuperList<T> where T : class
[ProtoMember(1)]
private List<SuperListItem<T>> _items = new List<SuperListItem<T>>();
public SuperList()
public int IndexOf(T item)
int indexOf = -1;
for (int index = 0; index < _items.Count; index++)
if (_items[index].Item == item)
indexOf = index;
break;
return indexOf;
public void Insert(int index, T item)
_items.Insert(index, new SuperListItem<T>(item));
public void RemoveAt(int index)
_items.RemoveAt(index);
public T this[int index]
get
return _items[index].Item;
set
_items[index] = new SuperListItem<T>(value);
public void Add(T item)
_items.Add(new SuperListItem<T>(item));
public void Clear()
_items.Clear();
public bool Contains(T item)
bool contains = false;
foreach (var listItem in _items)
if (listItem.Item == item)
contains = true;
break;
return contains;
public void CopyTo(T[] array, int arrayIndex)
for (int index = arrayIndex; index < _items.Count; index++)
array[index] = _items[index].Item;
public int Count
get return _items.Count;
public bool IsReadOnly
get return false;
public bool Remove(T item)
SuperListItem<T> itemToRemove = null;
foreach (var listItem in _items)
if (listItem.Item == item)
itemToRemove = listItem;
break;
if (itemToRemove != null)
_items.Remove(itemToRemove);
return itemToRemove != null;
public IEnumerator<T> GetEnumerator()
foreach(var listItem in _items)
yield return listItem.Item;
[ProtoContract]
public class SuperListItem<T>
[ProtoMember(1, AsReference = true)]
private readonly T _item;
public T Item get return _item;
private SuperListItem()
public SuperListItem(T item)
_item = item;
我有如下的序列化测试代码:
[ProtoContract]
public class Thing
[ProtoMember(1)]
private readonly string _name;
public string Name get return _name;
private Thing()
public Thing(string name)
_name = name;
public class ProtoTest3
public void Serialize()
SuperList<Thing> list = GetListOfThings();
using (var fs = File.Create(@"c:\temp\things.bin"))
ProtoBuf.Serializer.Serialize(fs, list);
fs.Close();
using (var fs = File.OpenRead(@"c:\temp\things.bin"))
list = ProtoBuf.Serializer.Deserialize<SuperList<Thing>>(fs);
Debug.Assert(list[0] == list[2]);
fs.Close();
private SuperList<Thing> GetListOfThings()
var thing1 = new Thing("thing1");
var thing2 = new Thing("thing2");
var list = new SuperList<Thing>();
list.Add(thing1);
list.Add(thing2);
list.Add(thing1);
return list;
但是,当我运行代码时,我得到异常“没有为此对象定义无参数构造函数”。它只是 ProtoBuf.Net 中的一个限制,还是我做错了什么。有没有办法解决这个问题?
【问题讨论】:
【参考方案1】:澄清;列表的限制仅仅是 列表本身 不被视为参考。 项目 ,只要它们位于标记为AsReference
的成员上 - 例如:
[Test]
public void SerializeTheEasyWay()
var list = GetListOfThings();
using (var fs = File.Create(@"things.bin"))
ProtoBuf.Serializer.Serialize(fs, list);
fs.Close();
using (var fs = File.OpenRead(@"things.bin"))
list = ProtoBuf.Serializer.Deserialize<MyDto>(fs);
Assert.AreEqual(3, list.Things.Count);
Assert.AreNotSame(list.Things[0], list.Things[1]);
Assert.AreSame(list.Things[0], list.Things[2]);
fs.Close();
[ProtoContract]
public class MyDto
[ProtoMember(1, AsReference = true)]
public List<Thing> Things get; set;
private MyDto GetListOfThings()
var thing1 = new Thing("thing1");
var thing2 = new Thing("thing2");
var list = new List<Thing>();
list.Add(thing1);
list.Add(thing2);
list.Add(thing1);
return new MyDto Things = list;
(有趣的事实 - 这实际上是 一模一样 在电线上)
确实,但是,在这种情况下,它创建实例的方式似乎存在错误;它正在使用.ctor
并且失败了。我会调查并解决这个问题,但以下方法也可以:
1:将无参数.ctor
公开:
public Thing()
2:或者,禁用.ctor
:
[ProtoContract(SkipConstructor = true)]
public class Thing
...
我将调查为什么私有无参数构造函数在这种情况下不满意。
【讨论】:
感谢 Marc,在“Thing”类上公开构造函数解决了我原来的问题。我曾假设构造函数错误只是 AsReference 不可用于列表的副产品(因为如果我删除了 AsReference,它与私有构造函数一起工作)。 @EasyTimer 是的,在这种情况下,它与对象创建有关。以上是关于列表的 Protobuf.net 对象图序列化的主要内容,如果未能解决你的问题,请参考以下文章