2011-09-08 63 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是的,在這種情況下,它與對象創建有關。 –