使用protobuf-net序列化不可变集合

时间:2013-05-02 04:10:10

标签: c# .net immutability protobuf-net

我正在尝试使用protobuf-net序列化一个类,其中包含一个不可变集合作为成员。

集合类型ImmutableList<T>实现ICollection<T>,但为true属性返回IsReadOnly。因此,任何修改它的尝试都会引发异常。

Protobuf-net似乎依赖于在创建集合后能够调用Add(T)以填充它。这显然不适用于不可变集合,这是一种耻辱,因为protobuf-net与我的所有其他数据类型一起工作得非常好,这些数据类型也是不可变的。

所以我的问题是,我有哪些选项可以序列化这些集合?


ImmutableList<T>的代码如下:

public sealed class ImmutableList<T> : IList<T>, IList
{
    private readonly T[] m_Items;

    public ImmutableList(IEnumerable<T> source)
    {
        m_Items = source.ToArray();
    }

    public T[] ToArray()
    {
        T[] newArray = new T[m_Items.Length];
        m_Items.CopyTo(newArray, 0);
        return newArray;
    }

    private static void ThrowNotSupported()
    {
        throw new NotSupportedException("The attempted operation was not supported as the collection is read-only.");
    }

    #region IList<T> Members

    int IList.Add(object value)
    {
        ThrowNotSupported();
        return -1;
    }

    void IList.Clear()
    {
        ThrowNotSupported();
    }

    void IList<T>.Insert(int index, T item)
    {
        ThrowNotSupported();
    }

    void IList.Insert(int index, object value)
    {
        ThrowNotSupported();
    }

    void IList.Remove(object value)
    {
        ThrowNotSupported();
    }

    void IList.RemoveAt(int index)
    {
        ThrowNotSupported();
    }

    void IList<T>.RemoveAt(int index)
    {
        ThrowNotSupported();
    }

    T IList<T>.this[int index]
    {
        get
        {
            return m_Items[index];
        }
        set
        {
            ThrowNotSupported();
        }
    }

    object IList.this[int index]
    {
        get
        {
            return m_Items[index];
        }
        set
        {
            ThrowNotSupported();
        }
    }

    public T this[int index]
    {
        get
        {
            return m_Items[index];
        }
    }

    bool IList.Contains(object value)
    {
        return Array.IndexOf(m_Items, value) != -1;
    }

    int IList.IndexOf(object value)
    {
        return Array.IndexOf(m_Items, value);
    }

    public int IndexOf(T item)
    {
        return Array.IndexOf(m_Items, item);
    }

    bool IList.IsFixedSize
    {
        get
        {
            return true;
        }
    }

    #endregion

    #region ICollection<T> Members

    void ICollection<T>.Add(T item)
    {
        ThrowNotSupported();
    }

    void ICollection<T>.Clear()
    {
        ThrowNotSupported();
    }

    bool ICollection<T>.Remove(T item)
    {
        ThrowNotSupported();
        return false;
    }

    object ICollection.SyncRoot
    {
        get
        {
            return m_Items;
        }
    }

    bool ICollection.IsSynchronized
    {
        get
        {
            return true;
        }
    }

    public bool Contains(T item)
    {
        return IndexOf(item) != -1;
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        m_Items.CopyTo(array, arrayIndex);
    }

    void ICollection.CopyTo(Array array, int index)
    {
        m_Items.CopyTo(array, index);
    }

    public int Count
    {
        get
        {
            return m_Items.Length;
        }
    }

    public bool IsReadOnly
    {
        get
        {
            return true;
        }
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return ((IEnumerable<T>)m_Items).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return m_Items.GetEnumerator();
    }

    #endregion
}

1 个答案:

答案 0 :(得分:2)

目前没有人支持;但这似乎是一个合理的方案。这取决于你的意思(评论)“开箱即用”;如果你的意思是“今天,没有代码改变”,它将需要使用一个代理人来反对DTO,或一个将不可变列表暴露为可变列表的垫片属性;如果你的意思是“向前移动”,我怀疑我们可以查看采用(优先)IEnumerable[<T>]或(不太优选,但可行)T[]的列表构造函数,并在缓冲数据后简单地构造列表