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
}

Answers


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.


Need Your Help

Suggestions for implementing audit tables in SQL Server?

sql-server database audit

One simple method I've used in the past is basically just creating a second table whose structure mirrors the one I want to audit, and then create an update/delete trigger on the main table. Befor...

How to stop the p2 director from resolving optional dependencies for one of our plugins?

eclipse p2 pde

We have a PDE build creating a big p2 repository. We skip the p2 director during the PDE build to call the p2.director on a specific feature (a sub-feature of what has been built).

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.