0

I'm deserializing a JSON list to object[] and expectedly get an array of object. I'd like however to deserialize to more specific types. Is there a way to do that, possibly with supplying the exact type on serialization? Unfortunatly I'm not able to be more specific than object[] in my code...

using System.Text.Json;

namespace Tests.DeSerialize;

class Program
{
    public static void Main(string[] args)
    {
        object[] objs = new object[]{
            42,
            "foobar",
            false,
            new Example {
                Name = "example",
            }
        };
        foreach (var obj in objs)
        {
            Console.WriteLine(obj.GetType().Name);
        }

        var serialized = JsonSerializer.Serialize(objs);
        Console.WriteLine();
        Console.WriteLine(serialized);
        Console.WriteLine();

        object[] deSerializedObjs = JsonSerializer.Deserialize<object[]>(serialized);
        foreach (var obj in deSerializedObjs)
        {
            Console.WriteLine(obj.GetType().FullName);
        }
    }
}

public class Example
{
    public string Name { get; set; }

    public override string ToString() => $"{GetType().Name}(\"{Name}\")";
}

Output:

Int32
String
Boolean
Example

[42,"foobar",false,{"Name":"example"}]

System.Text.Json.JsonElement
System.Text.Json.JsonElement
System.Text.Json.JsonElement
System.Text.Json.JsonElement

Is there a way to somehow encode the exact type into the serialized text?

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Does `ObjectAsPrimitiveConverter ` from [this answer](https://stackoverflow.com/a/65974452/3744182) to [C# - Deserializing nested json to nested Dictionary](https://stackoverflow.com/q/65972825/3744182) do what you need? – dbc Nov 01 '22 at 11:49

2 Answers2

0

Yes. You'll just need to create a C# class for the objects you are serializing/deserializing.

// you can use more meaningful names for the classes/variables
public class Object
{
   public int MyInt { get; set; }
   public string MyStr { get; set; }
   public bool MyBool { get; set; }
   public Example Example{ get; set; }
}

public class Example
{
   public string Name { get; set; }
   // other variables that might be in the Example object
}

Serializing the object should work the same but when deserializing you'll want to make the small change:

// use the public class name and if expecting an array use a collection such as List
var deSerializedObjs = JsonSerializer.Deserialize<List<Object>>(serialized);
ProdigalTechie
  • 188
  • 1
  • 8
  • No. As I've said, I have to use object[],can't know the type of the list elements... – user20376912 Oct 31 '22 at 17:37
  • Sounds like you are trying to get to the [JsonElement ValueKind](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement?view=net-6.0) here is another [answer](https://stackoverflow.com/questions/63509179/asp-net-core-system-text-json-jsonvaluekind) that might be what you are looking for – ProdigalTechie Oct 31 '22 at 18:56
0

Here is a quick dirty solution. You might use it as a prototype to further develop your own works. The type name of a non-primitive type is added via anonymous class and hardcoded property names which is the dirty part.

using System.Text.Json;

namespace Tests.DeSerialize;

class Program
{
    public static void Main(string[] args)
    {

        object[] objs = new object[]{
            42,
            "foobar",
            false,
            new {
                Type = "Tests.DeSerialize.Example",
                Value = new Example{
                    Name = "example"
                }
            }
        };

        foreach (var obj in objs)
        {
            Console.WriteLine(obj.GetType().Name);
        }

        var serialized = JsonSerializer.Serialize(objs);
        Console.WriteLine();
        Console.WriteLine(serialized);
        Console.WriteLine();

        var deSerializedObjs = JsonSerializer.Deserialize<JsonElement[]>(serialized);
        foreach (var obj in deSerializedObjs)
        {
            Console.WriteLine(obj.MyDeserialize().GetType().FullName);
        }
    }
}

public static class JsonElementExtension
{
    public static Object MyDeserialize(this JsonElement jsonElement)
    {
        switch (jsonElement.ValueKind)
        {
            case JsonValueKind.String:
                return jsonElement.Deserialize(typeof(string));

            case JsonValueKind.Number:
                return jsonElement.Deserialize(typeof(int));

            case JsonValueKind.False:
            case JsonValueKind.True:
                return jsonElement.Deserialize(typeof(bool));

            case JsonValueKind.Array:
                return jsonElement.Deserialize(typeof(Array));

            case JsonValueKind.Object:

                return jsonElement.GetProperty("Value").Deserialize(Type.GetType(jsonElement.GetProperty("Type").GetString()));

            default:
                return jsonElement.Deserialize(typeof(object));
        }
    }
}

Output:

Int32
String
Boolean
<>f__AnonymousType0`2

[42,"foobar",false,{"Type":"Tests.DeSerialize.Example","Value":{"Name":"example"}}]

System.Int32
System.String
System.Boolean
Tests.DeSerialize.Example
victor6510
  • 1,191
  • 8
  • 14