2011-09-08 65 views
3

我知道Asobject不支持带protobuf.net的列表,所以我试图解决这个限制。我创建了一个称为SuperList自定义列表,其中包含包裹型SuperListItem的对象项目如下:Protobuf.net对象列表序列化

[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中的一个限制吗,还是我做错了什么?有没有解决这个问题的方法?

回答

4

澄清;列表上的限制仅仅是列表本身不作为参考。该项目,只要他们是在一个会员标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}; 
    } 

(和有趣的事实 - 这实际上是正是电线上的相同)

There does,但是,在这种情况下,它似乎是一个如何创建实例的错误;它正在使用.ctor并失败。我将调查和解决这个问题,但是下面还工作:

1:使参.ctor市民:

 public Thing() 
     { 
     } 

2:或替代,禁用.ctor

[ProtoContract(SkipConstructor = true)] 
    public class Thing 
    { ... 

我会调查为什么私人无参数构造函数在这种情况下不开心。

+0

谢谢Marc,使构造函数在“Thing”类中公开,解决了我原来的问题。我认为构造函数错误只是AsReference的副产品,不能用于列表(因为如果我删除了AsReference,它会与私有构造函数一起使用)。 –

+0

@EasyTimer是的,在这种情况下,它与对象创建有关。 –