I’m trying to integrate the awesome protobuf-net into an existing codebase, but am encountering a crash when it tries to handle a custom type. A small demonstration is below: it will throw an InvalidOperationException in ProtoBuf.Serializers.ListDecorator. But if you comment out the indexer (or remove the IEnumerable implementation) then it runs cleanly.
using System.Collections.Generic;
using ProtoBuf;
using System.Collections;
[ProtoContract]
public class MyClass : IEnumerable<int>
{
[ProtoMember(1, IsPacked = true)]
public int[] data { get; set; }
// Comment out this indexed property to prevent the crash
public int this[int i] { get { return data[i]; } set { data[i] = value; } }
public IEnumerator<int> GetEnumerator() { foreach (var x in data) yield return x; }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
static void Main(string[] args) { Serializer.PrepareSerializer<MyClass>(); }
}
Am I doing something wrong? How can I tell the protobuf-net Serializer to just ignore that Indexer property?
Thanks!
EDIT (Oct 10): Marc has kindly provided a fix in protobuf-net r447 via [ProtoContract(IgnoreListHandling = true)].
Your type looks suspiciously like a collection, and protobuf-net is indeed trying to handle it as such. One “fix” would be to add an
Add(int)method, as that is what it is going to want to use when deserializing. I am, however, investigating why the presence/absence of the indexer makes a difference here (that is not immediately obvious to me).Note that because this looks so much like a collection, the
[ProtoMember(...)]might not be used here. I’m not 100% certain until I find out what role the indexer is playing here.Ahah; k; found why the indexer is getting involved – essentially, after detecting
IEnumerable, it is trying to identify theTypeof the collection; it uses various cues:<T>inICollection<T>SomeTypeinAdd(SomeType)SomeTypein apublic SomeTime this[int index] {...}indexerof these, the only one that applies is the last. However, IMO it should probably also use the
<T>inIEnumerable<T>(I might tweak this) – this would at least make this scenario less bizarre (as would improving the error message, which I’ll do).To summarize, protobuf-net has lots of very particular handling for things that smell like collections; personally, I’d drop the
IEnumerable<T>support, and let callers go via.datainstead; the message will (at some point) display: