У меня есть объект C #. Я хочу сериализовать его в массив, а не в карту значения ключа.

Мой класс C #:

[JsonArray()]
public class Foo
{
    [JsonProperty(Order = 1)]
    public Boolean Bar = true;

    [JsonProperty(Order = 2)]
    public Boolean Baz = false;
}

Желаемый вывод JSON:

[true,false]

Фактический вывод JSON (если я удалю атрибут JsonArray вверху):

{"Bar":true,"Baz":false}

У меня есть большое количество объектов в сложной иерархии объектов, которые мне нужно сериализовать как массив, а не карту значения ключа. Я бы предпочел решение, которое не требует, чтобы объект, выполняющий сериализацию, знал что-либо о том, что он сериализует. Я хочу иметь возможность просто вызвать JsonConvert.SerializeObject (myThing) на объекте верхнего уровня и правильно сериализовать все подобъекты из-за атрибутов, которые они имеют на себе.

В настоящее время все мои объекты реализуют IEnumerable, а затем я вручную обучаю каждого из них, как возвращать свойства в правильном порядке, но это вызывает путаницу при работе на C #, потому что intellisense пытается предложить мне все операции LINQ с объектом. хотя ни один из них не подходит.

Я считаю, что возможно, хотя и не знаю как, добавить к Foo атрибут, указывающий на другой класс, который знает, как сериализовать Foo. Что-то вроде [JsonConverter(FooSerializer)], а затем FooSerializer будет реализовывать JsonConverter. Однако я изо всех сил пытаюсь найти много информации о том, как использовать JsonConverter для сериализации, большинство вопросов, которые люди задают, похоже, связаны с десериализацией.

2
Micah Zoltu 2 Янв 2014 в 06:56

2 ответа

Лучший ответ

Вот как можно написать такой конвертер.

[JsonConverter(typeof(FooConverter))]
public class Foo
{
    public bool Bar { get; set; }
    public bool Baz { get; set; }
}
public class FooConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var foo = value as Foo;
        var obj = new object[] { foo.Bar, foo.Baz };
        serializer.Serialize(writer, obj);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var arr = ReadArrayObject(reader, serializer);
        return new Foo
        {
            Bar = (bool)arr[0],
            Baz = (bool)arr[1],
        };
    }

    private JArray ReadArrayObject(JsonReader reader, JsonSerializer serializer)
    {
        var arr = serializer.Deserialize<JToken>(reader) as JArray;
        if (arr == null || arr.Count != 2)
            throw new JsonSerializationException("Expected array of length 2"); 
        return arr;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Foo);
    }
}

Когда дело доходит до сериализации / десериализации, мне легче преобразовать в / из общего представления вашего объекта, которое сериализатор мог бы распознать и интерпретировать по мере необходимости.

Сериализация (запись) была простой, поскольку вы хотели изменить представление вашего объекта Foo на массив значений, преобразовать его в массив значений и сериализовать его.

В целом десериализация (чтение) может быть немного сложнее. Но опять же подход тот же. Вы ожидаете массив логических значений. Десериализуйте в массив и управляйте им для создания вашего объекта. Здесь вы можете выполнить некоторые проверки, если хотите, как я показал.

Благодаря этому вы сможете довольно легко конвертировать строки JSON и обратно.

var str = "[[true,true],[true,false]]";
var foos = JsonConvert.DeserializeObject<Foo[]>(str);
var serialized = JsonConvert.SerializeObject(foos);
4
Jeff Mercado 2 Янв 2014 в 05:59

Сериализация в Json.NET задокументирована здесь, включая класс JsonConverterAttribute

1
norlesh 2 Янв 2014 в 03:03