msgpack / msgpack-cli

MessagePack implementation for Common Language Infrastructure / msgpack.org[C#]
http://msgpack.org
Apache License 2.0
835 stars 175 forks source link

Unable to serialize types that implement IEnumerable but are not collections #169

Closed samcragg closed 8 years ago

samcragg commented 8 years ago

We're trying to serialize a type that has different properties but also implements IEnumerable, which causes MsgPack to think it's a collection. Is there a way of marking the type so it can be serialized normally (the actual class has a lot of properties to have to create a custom serializer by hand). Here's a quick demo of what I mean:

[Serializable]
public class NonCollectionType : IEnumerable<int>
{
    public int Property { get; set; }

    public IEnumerator<int> GetEnumerator()
    {
        yield break;
    }

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

As soon as you try to call GetSerializer<NonCollectionType> it will throw an exception saying the Add method is missing. I've also tried to implement the interface explicitly, however, it still thinks it's a collection...

I've managed to smash the source to do what I want by modifying ReflectionExtensions.GetCollectionTraits and ReflectionExtensions.TryCreateCollectionTraitsForHasGetEnumeratorType to check if the add method is null before creating the collection traits, however, this causes some of the unit tests to fail.

Perhaps another option would be to add a property to the SerializationContext of NonCollectionTypes (similar to how you have DefaultCollectionTypes) that you can register your type with and then you can quickly check for that at the start of the GetCollectionTraits method (we're trying to avoid custom attributes as the assembly defining the datatypes doesn't have a reference to MsgPack)

Let me know if you like either of the ideas and I can submit a pull request.

yfakariya commented 8 years ago

Sorry, I thought naively that such types were extremely rare.

I think it is better to accept such type as just a non collection type, and add compatibility switch to disable such behavior.

samcragg commented 8 years ago

This is now working in version 0.7.0, thanks