Reputation: 1
I have such JSON:
{
"data": {
"name": "xxx",
"xxx": {
"id": "1",
"code": "12345",
"description": "Hello"
}
}
}
I want to deserialize it to custom C# classes. "data" is an object that contains two specific pairs: value of the first pair always will be a key for the second pair (e.g., { "name": "yyy", "yyy": "some_object"}). I've added two classes but I don't know how to set name for "DataResponse" property, because it's not static:
public sealed class Data
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "xxx")]
public DataResponse DataResponse { get; set; }
}
public sealed class DataResponse
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "code")]
public string Code { get; set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
}
Main code to deserialize this JSON:
Data data = JsonConvert.DeserializeObject<Data>(json);
// do some stuff with data...
Upvotes: 0
Views: 909
Reputation: 116786
You can do this with a simple JsonConverter
. For instance, if we make your Data
class be a generic class supporting any object value type, you would do:
public sealed class Root<T>
{
public Data<T> data { get; set; }
}
[JsonConverter(typeof(GenericDataResponseConverter))]
public sealed class Data<T>
{
public string Name { get; set; }
public T DataResponse { get; set; }
}
class GenericDataResponseConverter : JsonConverter
{
Type GetDataResponseType(Type objectType)
{
return (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Data<>) ? objectType.GetGenericArguments()[0] : null);
}
public override bool CanConvert(Type objectType)
{
return GetDataResponseType(objectType) != null;
}
object ReadJsonGeneric<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var data = ((Data<T>)existingValue) ?? new Data<T>();
var obj = JObject.Load(reader);
data.Name = (string)obj["name"];
data.DataResponse = obj[data.Name].ToObject<T>(serializer);
return data;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
var genericMethod = method.MakeGenericMethod(new[] { GetDataResponseType(objectType ) });
return genericMethod.Invoke(this, new object[] { reader, objectType, existingValue, serializer });
}
void WriteJsonGeneric<T>(JsonWriter writer, object value, JsonSerializer serializer)
{
var data = (Data<T>)value;
var dict = new Dictionary<string, object>
{
{ "name", data.Name },
{ data.Name, data.DataResponse },
};
serializer.Serialize(writer, dict);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var method = GetType().GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
var genericMethod = method.MakeGenericMethod(new[] { GetDataResponseType(value.GetType()) });
genericMethod.Invoke(this, new object[] { writer, value, serializer });
}
}
Then, use it like:
var root = JsonConvert.DeserializeObject<Root<DataResponse>>(jsonString);
Debug.WriteLine(JsonConvert.SerializeObject(root, Formatting.Indented));
If you don't need the generic DataResponse
type, it becomes even easier:
public sealed class Root
{
public Data data { get; set; }
}
[JsonConverter(typeof(DataResponseConverter))]
public sealed class Data
{
public string Name { get; set; }
public DataResponse DataResponse { get; set; }
}
class DataResponseConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Data);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var data = ((Data)existingValue) ?? new Data();
var obj = JObject.Load(reader);
data.Name = (string)obj["name"];
data.DataResponse = obj[data.Name].ToObject<DataResponse>(serializer);
return data;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var data = (Data)value;
var dict = new Dictionary<string, object>
{
{ "name", data.Name },
{ data.Name, data.DataResponse },
};
serializer.Serialize(writer, dict);
}
}
Upvotes: 1