2

I have a C# object. I want to serialize it to an array rather than a key-value map.

My C# class:

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

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

The desired JSON output:

[true,false]

The actual JSON output (if I remove the JsonArray attribute at the top):

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

I have a large number of objects in a complex object hierarchy that I need to have serialized as an array rather than key-value map. I would prefer a solution that doesn't require that the thing doing the serialization know anything about what it is serializing. I want to be able to just call JsonConvert.SerializeObject(myThing) on a top level object and have all of the sub-objects serialize correctly due to attributes they have on themselves.

Currently, I have all of my objects implement IEnumerable and then I manually teach each one of them how to return the properties in the correct order but this causes confusion when working in C# because intellisense tries to offer me all of the LINQ operations on the object even though none of them are appropriate.

I believe it is possible, though I don't know how, to add an attribute to Foo that points at another class that knows how to serialize Foo. Something like [JsonConverter(FooSerializer)] and then FooSerializer would implement JsonConverter. However, I am struggling to find much information on how to use JsonConverter for serialization, most of the questions people ask seem to be related to deserialization.

2 Answers 2

4

Here's how you could write such a converter.

[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);
    }
}

When it comes to serialization/deserialization, I find it easier to convert to/from a generic representation of your object that the serializer could recognize and interpret it as needed.

Serializing (writing) was simple, since you wanted to change the representation of your Foo object to an array of values, convert it to an array of values and serialize that.

Deserializing (reading) could be a bit more difficult in general. But again, the approach is the same. You're expecting an array of boolean values. Deserialize to an array and manipulate that to create your object. Here you could perform some validations if you wanted to as I've shown.

With this, you should be able to convert to and from JSON strings quite easily.

var str = "[[true,true],[true,false]]";
var foos = JsonConvert.DeserializeObject<Foo[]>(str);
var serialized = JsonConvert.SerializeObject(foos);
Sign up to request clarification or add additional context in comments.

Comments

1

Serialization in Json.NET is documented here including the JsonConverterAttribute class

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.