Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialising JSON into a generic object

I have a three classes

public class A<T>
{
    public bool Success {get; set;}
    public string Reason {get; set;}
    public T Data {get; set;}
}

public class B
{ 
    public string Token {get; set;}
}

public class C
{
    public int SomeInt {get; set;}
    public string SomeString {get; set;}
    public double SomeDouble {get; set;}
}

I call my web service and pass in A or A to deserialise into like this

 async Task<T> MyTask<T>(...) (where T is A<B> or A<C>)

The service works fine and returns some JSON which if I try and to deserialise into a var, I'm getting nothing deserialised

To deserialise, I'm using

 var foo = JsonConvert.DeserializeObject<T>(response.Content);

Is there a limitation to how I can deserialise the object so I can only use a base class rather than this form of class?

like image 955
Nodoid Avatar asked Jan 16 '26 19:01

Nodoid


1 Answers

Yes, you can not just pass A because A is not base class, it is generic class and does not exists on its own.

C# generates generic classes during compile time, which means if you use A<B> in your code, C# will generate something like:

public class generated_A_B
{
    public bool Success { get; set; }
    public string Reason { get; set; }
    public B Data { get; set; }
}

Nothing will be generated for A<C>, if not explicitly used. Reason is obvious, if you generate classes for every single combination of the A, you will bloat your code.

In your current situation it is better to just call them explicitly

void Main()
{
    CallAB();
    CallAC();
}

A<B> CallAB()
{
    return ServiceCall<A<B>>("/api/ab");
}

A<C> CallAC()
{
    return ServiceCall<A<C>>("/api/ac");
}

If you really want to get "generic" A, you should make A an actual base class and have your API to return the type of Data. In my example I just use Name of the type, but you probably should use FullName that includes namespace, to avoid name conflicts.

void Main()
{
    var json = @"
    {
        ""success"": true,
        ""reason"": ""All good"",
        ""type"": ""B"",
        ""data"": {
            ""token"": ""1234-5678""
        }
    }";
    var foo = JsonConvert.DeserializeObject<A>(json);
    var type = Assembly.GetExecutingAssembly().GetTypes().Where(i => i.IsClass && i.Name == foo.Type).FirstOrDefault();
    if (type == null)
    {
        throw new InvalidOperationException(string.Format("Type {0} not found", foo.Type));
    }
    var data = foo.Data.ToObject(type);
}

public class A
{
    public bool Success { get; set; }
    public string Reason { get; set; }
    public string Type { get; set; }
    public JToken Data { get; set; }
}

public class B
{
    public string Token { get; set; }
}
like image 175
Yaroslav Veremenko Avatar answered Jan 19 '26 09:01

Yaroslav Veremenko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!