我知道带有protobuf.net的列表不支持AsReference,所以我尝试了解决这个限制的方法.我创建了一个名为SuperList的自定义列表,其中包含包含在SuperListItem类型的对象中的项目,如下所示: [ProtoC
[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中的一个限制,还是我做错了什么.有没有解决这个问题的方法?
澄清;列表的限制只是列表本身不被视为参考.这些项目,只要它们在标记为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:
public Thing() { }
2:或者,禁用.ctor:
[ProtoContract(SkipConstructor = true)] public class Thing { ...
我将研究为什么私有无参数构造函数在这种情况下不满意.