In this article, we’ll explore different ways to convert a JObject to a dictionary in C#.

To download the source code for this article, you can visit our GitHub repository.

In C# programming, a JObject is a fundamental component provided by the Json.NET library, also known as Newtonsoft.Json. Moreover, it represents a JSON object, allowing developers to work with JSON data in a structured and convenient manner. JObject is a part of the broader family of classes in Json.NET that facilitate the parsing, manipulation, and creation of JSON data. The need to convert a JObject to a dictionary in C# arises when working with JSON data in a more traditional and versatile context.

While JObject provides a dynamic and convenient way to interact with JSON, there are scenarios where a dictionary is a more suitable data structure.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Understanding the JObject

A JObject is a collection of key-value pairs. Each key is a string, and each value can be a simple data type, another JObject, JArray, or even null. This flexibility makes JObject a powerful tool for handling complex JSON structures in C# applications.

Let’s see the structure of JObject:

var person = new JObject(
    new JProperty("Name", "John Smith"),
    new JProperty("BirthDate", new DateTime(1983, 3, 20)),
    new JProperty("Hobbies", new JArray("Play football", "Programming")),
    new JProperty("Extra", new JObject(
        new JProperty("Age", 27),
        new JProperty("Phone", new JArray(1, 2, 3))
    ))
);

Here, we create a JSON-like object representing information about a person using the JObject class from the Json.NET library in C#.

The person object has properties like “Name,” set to “John Smith,” “BirthDate,” set to March 20, 1983, and “Hobbies,” which is an array containing “Play football” and “Programming.”

Additionally, there’s an “Extra” property, another nested JObject. This inner object holds properties like “Age,” set to 27, and “Phone,” an array with values 1, 2, and 3.

It’s a structured way to model complex data with different types, such as strings, numbers, and arrays, making it convenient for representing hierarchical and detailed information about a person in a format that resembles JSON.

Now, let’s dive into different approaches to how to convert a JObject to a Dictionary.

Convert a JObject to a Dictionary Using Traditional Iteration

In the traditional iteration method, we manually traverse the JObject, extracting key-value pairs at each level. The process involves iterating through the properties of the JObject and handling nested structures using recursive calls.

First, let’s create a method to convert a JObject to a Dictionary:

public static class JObjectConverter
{
    public static Dictionary<string, object> ConvertJObjectToDictionary(JObject jsonObject)
    {
        Dictionary<string, object> result = new();

        foreach (var property in jsonObject.Properties())
        {
            string key = property.Name;
            JToken value = property.Value;

            switch (value.Type)
            {
                case JTokenType.Object:
                    if (value is JObject nestedObject)
                    {
                        result[key] = ConvertJObjectToDictionary(nestedObject);
                    }
                    break;
                case JTokenType.Array:
                    if(value is JArray array)
                    {
                        result[key] = ConvertJArrayToList(array);
                    }
                    break;
                default:
                    result[key] = ((JValue)value).Value!;
                    break;
            }
        }

        return result;
    }
}

Here, we start creating a static class JObjectConverter and define a ConvertJObjectToDictionary() method that accepts jsonObject. 

Next, we iterate through the properties of the jsonObject. For each property, we extract the name and value. Inside the loop, we use a switch statement to handle different types of values associated with each property.

If the value is a JTokenType.Object, then we recursively call the ConvertJObjectToDictionary() method to convert the nested object into another Dictionary<string, object>.

If the value is a JTokenType.Array, we call the ConvertJArrayToList() method to handle the array and convert it into a List<object>. In the default case, we add the value to the result dictionary.

We use recursion to handle nested structures within the JSON, making this code useful for converting complex JSON objects into a more accessible dictionary format.

Next, let’s create the ConvertJArrayToList() method to convert JArray to List:

private static List<object> ConvertJArrayToList(JArray jArray)
{
    var result = new List<object>();

    foreach (var item in jArray)
    {
        switch (item.Type)
        {
            case JTokenType.Object:
                if (item is JObject nestedObject)
                {
                    result.Add(ConvertJObjectToDictionary(nestedObject));
                }
                break;
            case JTokenType.Array:
                if (item is JArray array)
                {
                    result.Add(ConvertJArrayToList(array));
                }
                break;
            default:
                result.Add(((JValue)item).Value!);
                break;
        }
    }

    return result;
}

To start, we create a ConvertJArrayToList() method that accepts jArray as the input parameter. Inside the loop, we use a switch statement to handle different types of items within the array.

Depending on the type of the value, whether it’s another object, an array, or a simple value like a string or number, we appropriately convert it and add it to the result list object.

Now, let’s invoke the method:

JObjectConverter.ConvertJObjectToDictionary(person);

We call the ConvertJObjectToDictionary() method, passing the person object that we created in the beginning.

Let’s inspect the output:

{
  "Name": "John Smith",
  "BirthDate": "1983-03-20T00:00:00",
  "Hobbies": [
    "Play football",
    "Programming"
  ],
  "Extra": {
    "Age": 27,
    "Phone": [
      1,
      2,
      3
    ]
  }
}

Here, we observe the transformation of the original JObject into a structured set of key-value pairs. Each property of the JObject, such as “Name,” “BirthDate,” “Hobbies,” and “Extra,” have been effectively converted into their corresponding key with associated values.

Convert a JObject to a Dictionary Using Json.NET Library

Json.NET is a popular and versatile JSON processing library for .NET applications. It simplifies the serialization and deserialization of JSON data, offering robust features and high performance. It has become the standard for working with JSON in the C# ecosystem.

The JObject class in Json.NET provides a convenient ToObject<T>() method that allows developers to convert a JObject instance to an object of a specified type T.

Let’s start by creating a new method in the JObjectConverter class:

public static Dictionary<string, object>? ConvertUsingNewtonsoftJson(JObject person)
{
    var result = person.ToObject<Dictionary<string, object>>();

    return result;
}

Here, we define a ConvertUsingNewtonsoftJson() method that accepts a person object of type JObject.

Subsequently, we invoke the ToObject() method of the person object, specifying the target type as Dictionary<string, object>. This method allows for the direct conversion of a JObject to a dictionary.

As a last step, let’s invoke the method:

JObjectConverter.ConvertUsingNewtonsoftJson(person);

Similarly, we call the ConvertUsingNewtonsoftJson() method to convert the JObject to a dictionary.

Convert Using LINQ Queries

Language Integrated Query is a powerful feature in C# that allows us to query and manipulate data directly within the language using an SQL-like syntax.

We use LINQ for converting a JObject to a dictionary, and we leverage its query capabilities to traverse the properties and values of the JObject. LINQ allows us to express the conversion logic concisely and declaratively.

Let’s start defining a method:

public static Dictionary<string, object> ConvertUsingLinq(JObject jsonObject)
{
    var result = jsonObject
                .Properties()
                .ToDictionary(
                    property => property.Name,
                    property => ConvertJToken(property.Value));

    return result;
}

We begin by extracting all properties of the JObject and then employs the LINQ ToDictionary() method, where each property’s name becomes a key, and we invoke the ConvertJToken() method with the associated value.

Next, let’s create the ConvertJToken() method:

private static object ConvertJToken(JToken token)
{
    switch (token.Type)
    {
        case JTokenType.Object:
            if (token is JObject personObject)
            {
                return ConvertUsingLinq(personObject);
            }
            break;

        case JTokenType.Array:
            if (token is JArray jArray)
            {
                return ConvertJArrayToListUsingLinq(jArray);
            }
            break;

        default:
            return ((JValue)token).Value!;
    }

    throw new InvalidOperationException("Unsupported JToken type");
}

Here, we use a switch statement to evaluate the type of input token. If the token is of type JTokenType.Object, we call the ConvertUsingLinq() method to convert the JSON object to a C# dictionary using LINQ.

If the token is of type JTokenType.Array, we call the ConvertJArrayToListUsingLinq() method to convert the JSON array to a C# list using LINQ. In the default case, we return the Value property of the token.

Finally, let’s define another method:

private static List<object> ConvertJArrayToListUsingLinq(JArray jArray)
{
    return jArray.Select(ConvertJToken).ToList();
}

We use the LINQ Select() method to project each item in jArray into its converted form. Then, we apply ConvertJToken() method to each item during this projection.

Finally, we use the ToList() method on the result of the Select operation to convert the projected items into a List<object>.

So, let’s call the ConvertUsingLinq() method:

JObjectConverter.ConvertUsingLinq(person);

Similarly, we call the ConvertUsingLinq() method to convert the JObject to a dictionary and observe the same output as aforementioned.

Creating a Custom Extension Method for Converting JObject to Dictionary

Extension methods in C# allow us to add new methods to existing types without modifying them. They enhance the readability and maintainability of code by providing a way to extend the functionality of classes or interfaces without altering their source code.

Let’s start creating an extension method:

public static class JObjectExtensions
{
    public static Dictionary<string, object?> ToDictionary(this JObject jObject)
    {
        Dictionary<string, object?> result = new();

        foreach (var property in jObject.Properties())
        {
            string key = property.Name;
            JToken value = property.Value;

            result[key] = value?.ToObject<object>() ?? "";
        }

        return result;
    }
}

We start by creating a ToDictionary() extension method inside the JObjectExtensions class. Subsequently, we use a foreach loop to iterate through each property of the input JObject.

Inside the loop, we extract the name of each property and its corresponding value. Then, we invoke the ToObject() method to convert the JToken to its C# equivalent, and we assign the result to the corresponding key in the result dictionary.

Now, let’s invoke the extension method:

person.ToDictionary()

We invoke the ToDictionary() extension method to convert a JObject to a dictionary.

Benchmarking JObject to Dictionary Conversion

Let’s evaluate the four approaches for converting JObject to a dictionary we’ve covered so far. We will perform a benchmark with the BenchmarkDotNet library to measure the time performance for four approaches.

Let’s assess the benchmark results:

| Method                                | Mean       | Error    | StdDev    | Median     |
|-------------------------------------- |-----------:|---------:|----------:|-----------:|
| ToDictionaryUsingTraditionalIteration |   700.4 ns | 13.88 ns |  31.62 ns |   689.1 ns |
| ToDictionaryUsingLinq                 |   718.5 ns |  9.55 ns |   7.97 ns |   718.5 ns |
| ToDictionaryUsingJsonNet              | 3,302.0 ns | 64.59 ns | 116.47 ns | 3,257.4 ns |
| ToDictionaryUsinExtensionMethod       | 3,372.0 ns | 65.64 ns |  92.02 ns | 3,334.1 ns |

The traditional iteration and LINQ-based methods show the fastest mean execution times, with the traditional iteration being the quickest.

The Json.NET and extension method approaches have higher mean execution times, indicating a trade-off for their respective advantages, such as ease of use or library integration.

However, it’s important to note that the extension method, while potentially offering a fluent syntax, may come with a slightly higher performance cost.

Factors for Choosing the Appropriate Method

Choosing the appropriate method for converting a JObject to a dictionary in C# depends on various factors.

A traditional iteration method may be straightforward and efficient if the JSON structure is simple and lacks deep nesting. Traditional iteration allows for fine-grained error handling at each conversion process step.

On the other hand, for complex structures with nested objects and arrays, Json.NET’s ToObject() method offers a concise and expressive way to handle intricacies. Furthermore, generics allow us to specify the desired data types, providing more control over the resulting dictionary’s value types.

In addition, if performance is a critical factor and we want to leverage the expressiveness of LINQ, using LINQ queries might be a good choice.

We can enhance the readability of the code by providing a fluent and natural syntax when we use extension methods appropriately.

Conclusion

In this article, we explored various approaches to converting JObject to dictionary.

In conclusion, the choice of the appropriate method depends on the specific characteristics of the JSON data, performance considerations, code readability, ease of use, and future scalability requirements.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!