Отключить класс IEnumerable с помощью Newtonsoft Json.Net

У меня есть проект, который в настоящее время использует Json.Net для классов десериализации Json, таких как:

public class Foo {
    public Guid FooGuid { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; }
}

public class Bar {
    public Guid BarGuid { get; set; }
    public string Description { get; set; }
}

Пока это работает нормально.

Чтобы упростить итерацию в один момент, я выполнил Foo class IEnumerable<Bar> следующим образом:

public class Foo : IEnumerable<Bar> {
    public Guid FooGuid { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; }

    public IEnumerator<Bar> GetEnumerator()
    {
        return Bars.GetEnumerator();
    }

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

public class Bar {
    public Guid BarGuid { get; set; }
    public string Description { get; set; }
}

Но тогда это не позволяет десериализовать объект. Ошибка запуталась, поскольку он сказал, что не может десериализовать поле FooGuid, но удаление интерфейса IEnumerable снова работает.

Проблема одинакова в средах MonoTouch и MonoDroid в симуляторе или устройстве.

Любая подсказка о том, как заставить его работать?


Добавлен код для воспроизведения этой проблемы:

public static class Tests {
    public static void SerializeAndDeserializeFoo() {
        // Serialize and deserialize Foo class
        var element = new Foo
        {
            FooGuid = Guid.NewGuid(),
            Name = "Foo name",
            Bars = new List<Bar> {
                new Bar { BarGuid = Guid.NewGuid(), Description = "Bar description" },
                new Bar { BarGuid = Guid.NewGuid(), Description = "Bar description" },
                new Bar { BarGuid = Guid.NewGuid(), Description = "Bar description" }
            }
        };

        var serializedObject = JsonConvert.SerializeObject(element);
        Console.WriteLine("Serialized Foo element: {0}", serializedObject);

        // Exception if Foo implements IEnumerable
        var deserializedObject = JsonConvert.DeserializeObject<Foo>(serializedObject);
        Console.WriteLine("Foo deserialization worked!");
    }

    public static void SerializeAndDeserializeEnumerableFoo() {
        // Serialize and deserialize Foo class
        var element = new EnumerableFoo
        {
            FooGuid = Guid.NewGuid(),
            Name = "Foo name",
            Bars = new List<Bar> {
                new Bar { BarGuid = Guid.NewGuid(), Description = "Bar description" },
                new Bar { BarGuid = Guid.NewGuid(), Description = "Bar description" },
                new Bar { BarGuid = Guid.NewGuid(), Description = "Bar description" }
            }
        };

        var serializedObject = JsonConvert.SerializeObject(element);
        Console.WriteLine("Serialized EnumerableFoo element: {0}", serializedObject);

        try {
            // Exception if Foo implements IEnumerable
            var deserializedObject = JsonConvert.DeserializeObject<EnumerableFoo>(serializedObject);
            Console.WriteLine("EnumerableFoo deserialization worked!");
        }
        catch (Exception e){
            Console.WriteLine("EnumerableFoo deserialization failed!");
            throw;
        }
    }
}

public class EnumerableFoo : IEnumerable<Bar> {
    public Guid FooGuid { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; }

    public IEnumerator<Bar> GetEnumerator()
    {
        return Bars.GetEnumerator();
    }

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

public class Foo {
    public Guid FooGuid { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; }
}

public class Bar {
    public Guid BarGuid { get; set; }
    public string Description { get; set; }
}

Пример проекта: https://www.dropbox.com/s/27i58aiz71dylkw/IEnumerableJson.zip

Ответы

Ответ 1

От Документация Json.Net:

IEnumerable, списки и массивы

Списки .NET(типы, наследующие от IEnumerable) и массивы .NET преобразуются в массивы JSON. Поскольку массивы JSON поддерживают только диапазон значений, а не свойства, любые дополнительные свойства и поля, объявленные в коллекциях .NET, не сериализуются. В ситуациях, когда массив JSON не нужен, JsonObjectAttribute может быть помещен в тип .NET, который реализует IEnumerable, чтобы заставить тип быть сериализованным как объект JSON.

Другими словами, поскольку ваш класс реализует IEnumerable<T>, Json.Net считает, что это список. Чтобы обойти это, просто украсьте свой класс атрибутом [JsonObject]. Это заставит Json.Net сериализовать и десериализовать его как обычный класс, который вам нужен в этом случае.

[JsonObject]
public class EnumerableFoo : IEnumerable<Bar>
{
    ...
}