C# 使用未知值类型反序列化JSON
使用C#特别是JSON.net如何处理具有动态值的JSON对象。例如: { “消息id”:“123-456”, “数据”:[“数据”,“列表”], “类型”:“消息类型1” } { “消息id”:“123-457”, “数据”:“我的数据字符串”, “类型”:“消息类型2” } { “消息id”:“123-458”, “数据”:{“key1”:“value1”,“key2”:“value2”}, “类型”:“MSG_类型3” } “数据”值可以是任何类型。在C#中,我定义了一个包含这些属性的ServiceMessage类,但“数据”应该是什么类型的属性。我在看一个JToken或JContainer,但我不确定最好的实现方式C# 使用未知值类型反序列化JSON,c#,json,json.net,C#,Json,Json.net,使用C#特别是JSON.net如何处理具有动态值的JSON对象。例如: { “消息id”:“123-456”, “数据”:[“数据”,“列表”], “类型”:“消息类型1” } { “消息id”:“123-457”, “数据”:“我的数据字符串”, “类型”:“消息类型2” } { “消息id”:“123-458”, “数据”:{“key1”:“value1”,“key2”:“value2”}, “类型”:“MSG_类型3” } “数据”值可以是任何类型。在C#中,我定义了一个包含这些属性的Se
public class ServiceMessage
{
public string message_id { get; set; }
public JContainer data { get; set; }
public string type { get; set; }
public string getJSON()
{
string json = JsonConvert.SerializeObject(this);
return json;
}
public void setJSON(string json)
{
dynamic jsonObj = JsonConvert.DeserializeObject(json);
this.message_id = jsonObj.message_id;
this.type = jsonObj.type;
this.data = // what goes here.
}
}
你在用这些数据做什么?将其保留为json字符串并在需要数据时处理是有意义的。我不确定这是否正确,但这就是我想到的。 我向他借了很多钱
class ServiceMessageConverter:CustomCreationConverter
{
公共覆盖服务消息创建(类型objectType)
{
返回新的ServiceMessage();
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
var msg=new ServiceMessage();
字符串数据_string=“”;
//获取对象的道具数组,这样我就可以检查JSON道具s/b是否映射到它
var objProps=objectType.GetProperties().Select(p=>p.Name.ToLower()).ToArray();
while(reader.Read())
{
if(reader.Value==null)
{
继续;
}
//读取属性名
字符串readerValue=reader.Value.ToString().ToLower();
//读取属性值
if(reader.Read())
{
//确保将复杂类型保存为字符串
if(readerValue.ToLower()=“数据”)
{
if(reader.TokenType==JsonToken.StartObject)
{
动态数据_obj=序列化程序。反序列化(读取器);
data_string=data_obj.ToString();
}
else if(reader.TokenType==JsonToken.StartArray)
{
动态数据_obj=序列化程序。反序列化(读取器);
data_string=data_obj.ToString();
}
其他的
{
data_string=reader.Value.ToString();
}
//将数据元素值填充到ServiceMessage中
PropertyInfo pi=msg.GetType()。
GetProperty(“数据”,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
pi.SetValue(消息,数据字符串);
}
其他的
{
//将值填充到ServiceMessage中
PropertyInfo pi=msg.GetType()。
GetProperty(readerValue,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var convertedValue=Convert.ChangeType(reader.Value,pi.PropertyType);
pi.SetValue(msg,convertedValue,null);
}
}
}
返回味精;
}
}
一旦知道消息id和消息类型,则检索数据元素。JSON来自python制作者(但它可以是任何东西)。我曾考虑将数据保存为JSON字符串,然后在需要时进行处理,但我不确定是否有更好的方法?有一些信息-但基于对象当前的外观。我将把它作为字符串保留,因为不管怎样,最终都必须反序列化。至少当你按消息类型把它拉出来的时候,我假设至少,这个结构会遵循一个固定的模式,并且允许你像最初一样继续。谢谢。作为一个新手,我在反序列化“数据”,似乎JSON.Net检测到了JSON数组,对象,那么,我如何确保特定字段保持为字符串呢?所以做一些调查,看起来我可能需要一个自定义转换器来为我执行部分反序列化。您知道它们在编译时是数据对象的实际结构还是每条消息都包含不同的值?您希望如何查找数据值?我将根据消息类型了解数据对象的实际结构。如果我知道消息是MSG_TYPE1,那么我就会知道对象的结构。@如果不知道访问对象的确切方式,就很难拥有强类型对象。你可以用泛型做一些事情,但我很肯定这会带来更多的麻烦。一旦数据通过电线,您希望如何访问它?
class ServiceMessageConverter : CustomCreationConverter<ServiceMessage>
{
public override ServiceMessage Create(Type objectType)
{
return new ServiceMessage();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var msg = new ServiceMessage();
string data_string = "";
//get an array of the object's props so I can check if the JSON prop s/b mapped to it
var objProps = objectType.GetProperties().Select(p => p.Name.ToLower()).ToArray();
while (reader.Read())
{
if (reader.Value == null)
{
continue;
}
// read the property name
string readerValue = reader.Value.ToString().ToLower();
// read the property value
if (reader.Read())
{
// make sure the complex types are saved as strings
if (readerValue.ToLower() == "data")
{
if (reader.TokenType == JsonToken.StartObject)
{
dynamic data_obj = serializer.Deserialize(reader);
data_string = data_obj.ToString();
}
else if (reader.TokenType == JsonToken.StartArray)
{
dynamic data_obj = serializer.Deserialize(reader);
data_string = data_obj.ToString();
}
else
{
data_string = reader.Value.ToString();
}
// stuff the data element value into the ServiceMessage
PropertyInfo pi = msg.GetType().
GetProperty("data", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
pi.SetValue(msg, data_string);
}
else
{
// stuff the value into the ServiceMessage
PropertyInfo pi = msg.GetType().
GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType);
pi.SetValue(msg, convertedValue, null);
}
}
}
return msg;
}
}