Jacob Stanley
Jacob Stanley

Reputation: 4824

Serializing immutable collections with protobuf-net

I'm trying to serialize a class with protobuf-net which contains an immutable collection as a member.

The collection type, ImmutableList<T>, implements ICollection<T> but returns true for the IsReadOnly property. So any attempts to modify it throw an exception.

Protobuf-net seems to rely on being able to call Add(T) after creating a collection in order to populate it. This obviously won't work with an immutable collection, which is a shame because protobuf-net works beautifully with all my other data types, which are also immutable.

So my question is, what options do I have to be able to serialize such collections?


The code for ImmutableList<T> is listed below:

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
}

Upvotes: 2

Views: 1011

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1063403

At the moment there is no support for that; but it seems a reasonable scenario. It depends on what you mean (comments) by "out of the box"; if you mean "today, without code changed", it would need to use a surrogate against the DTO, or a shim property that exposed the immutable list as a mutable one; if you mean "moving forwards", I suspect we could look at list-constructors that take (perferable) IEnumerable[<T>] or (less preferable, but doable) T[], and simply construct the list after buffering the data.

Upvotes: 2

Related Questions