【C#】复杂Json的反序列 + 任意Json获取
前言
本文用到的Json库是:
以前用这个
但是,现在微软主推上面这个,性能更优,用法其实差不多。
复杂结构的JSON
如何将一个复杂类型的JSON进行反序列化。那就是如何把json拆解成一个个子类的过程。
如下我有这样一个json字符串:
{
"success": True,
"message": "操作成功!",
"code": 200,
"result": {
"ruleColumn": [
{
"columnChName": "孔宽1"
},
{
"columnChName": "孔从中心偏移3"
},
{
"columnChName": "孔从中心偏移6"
},
{
"columnChName": "孔从中心偏移5"
},
{
"columnChName": "孔从中心偏移2"
},
{
"columnChName": "孔长3"
},
{
"columnChName": "孔从中心偏移7"
},
{
"columnChName": "孔从中心偏移4"
},
{
"columnChName": "孔中到Y中心8"
},
{
"columnChName": "孔中到X中心9"
}
],
"number": 5,
"titleColumn": [
{
"columnChName": "工序",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "日期",
"columnType": "date",
"selectValue": None
},
{
"columnChName": "班次",
"columnType": "select",
"selectValue": [
"A",
"B"
]
},
{
"columnChName": "测试时间",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "测试员",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "测试机台号",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "备注",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "生产机台",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "检验方式",
"columnType": "input",
"selectValue": None
},
{
"columnChName": "判定",
"columnType": "judge",
"selectValue": None
}
],
"projectDetailId": "1559817674652483586",
"rules": [
{
"columnChName": "孔宽1",
"nominalDim": 17.28,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 17.3,
"lsl": 17.26
},
{
"columnChName": "孔从中心偏移3",
"nominalDim": 17.28,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 17.3,
"lsl": 17.26
},
{
"columnChName": "孔从中心偏移6",
"nominalDim": 17.28,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 17.3,
"lsl": 17.26
},
{
"columnChName": "孔从中心偏移5",
"nominalDim": 13.84,
"tolMax": 0.05,
"tolMin": 0.05,
"usl": 13.89,
"lsl": 13.79
},
{
"columnChName": "孔从中心偏移2",
"nominalDim": 13.84,
"tolMax": 0.05,
"tolMin": 0.05,
"usl": 13.89,
"lsl": 13.79
},
{
"columnChName": "孔长3",
"nominalDim": 52.94,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 52.96,
"lsl": 52.92
},
{
"columnChName": "孔从中心偏移7",
"nominalDim": 49.75,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 49.77,
"lsl": 49.73
},
{
"columnChName": "孔从中心偏移4",
"nominalDim": 49.75,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 49.77,
"lsl": 49.73
},
{
"columnChName": "孔中到Y中心8",
"nominalDim": 43.99,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 44.01,
"lsl": 43.97
},
{
"columnChName": "孔中到X中心9",
"nominalDim": 16.23,
"tolMax": 0.02,
"tolMin": 0.02,
"usl": 16.25,
"lsl": 16.21
}
]
},
"timestamp": 1663056576303
}
其中result这个key对应的内容是可能发生变化的,所以这里可以用到泛型。大体不变的框架是这样的:
{
"success": True,
"message": "添加成功!",
"code": 200,
"result": None,
"timestamp": int(round(time.time() * 1000))
}
类的构造
那我先构造这个类,对于大的框架:
注意,类名并不重要(他代表的是大括号)重要的是属性的名称,需要和key的值保持一致:
public class WeiDaLiResult<T>
{
public bool success { get; set; }
public string message { get; set; }
public int code { get; set; }
public T result { get; set; }
public ulong timestamp { get; set; }
}
然后是针对当前result的部分,这里的技术关键是如何构造json数组,我们用到了IList接口:
#region item 项
public class RuleColumnItem
{
public string columnChName { get; set; }
}
public class TitleColumnItem
{
public string columnChName { get; set; }
public string columnType { get; set; }
public IList<string> selectValue { get; set; }
}
public class RulesItem
{
public string columnChName { get; set; }
public float nominalDim { get; set; }
public float tolMax { get; set; }
public float tolMin { get; set; }
public float usl { get; set; }
public float lsl { get; set; }
}
#endregion
public class SubResult
{
public IList<RuleColumnItem> ruleColumn { get; set; }
public int number { get; set; }
public IList<TitleColumnItem> titleColumn { get; set; }
public string projectDetailId { get; set; }
public IList<RulesItem> rules { get; set; }
}
反序列化过程调用
反序列化过程调用(注意泛型是如何被使用的):
var r = System.Text.Json.JsonSerializer.Deserialize<WeiDaLiResult<SubResult>>(str_json);
中文乱码解决
这里我们可以把这个options 保存到wpf的App类中,方便其他类调用。
public static JsonSerializerOptions options = new JsonSerializerOptions()
{
// 解决中文乱码问题
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All)
};
比如一个类想序列化成json字符串:
我们就可以用:
var byteArray = JsonSerializer.SerializeToUtf8Bytes(this, App.options);
完整代码如下:
public class ReturnInfo<T>
{
public bool success { get; set; }
public string message { get; set; }
public string code { get; set; }
public T result { get; set; }
public long timestamp
{
get
{
return DateTimeOffset.Now.ToUnixTimeSeconds();
}
}
public override string ToString()
{
var byteArray = JsonSerializer.SerializeToUtf8Bytes(this, App.options);
string str = System.Text.Encoding.UTF8.GetString(byteArray);
return str;
}
}
或者obj本身就是一个json,则使用:
obj.ToJsonString(options)
套路就是,json对象转换成字符串或者字节数组的时候,都会有重载函数,其中就有一个带options参数的,把这个options传入,就能解决乱码问题啦!
枚举的反序列化
这里在做一个优化:
将columnType这个字段序列化成枚举。
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ControlType
{
input = 0,
date,
select,
judge,
}
类改造
//改造前
public class TitleColumnItem
{
public string columnChName { get; set; }
public string columnType { get; set; }
public IList<string> selectValue { get; set; }
}
//改造后
public class TitleColumnItem
{
public string columnChName { get; set; }
public ControlType columnType { get; set; }
public IList<string> selectValue { get; set; }
}
注意,枚举要序列化,需要加一个特性:
[JsonConverter(typeof(JsonStringEnumConverter))]
任意Json获取
在有的情况下,我们只得到一个json字符串,并没有一个模板来进行序列化,也就是说,这个json的Key是不确定的,那么我们应该这么访问这个json字符串呢?
我们需要一个叫JsonDocument的类帮忙:
var je = System.Text.Json.JsonDocument.Parse(jsonStr);
比如我们的字符串是:
{"1长 X0":0.01, "12 长 X-26.89":0.07, "判定":"OK"}
我们就可以这么获取值:
var s = je.RootElement.GetProperty("1长 X0").GetDouble();
Json 格式化
想分行显示json,然后带缩进,本来Newtonsoft.Json是自带这个功能的:
string json = JsonConvert.SerializeObject(product, Formatting.Indented);
微软自带的这个包,我还没发现有这个功能,所以,这里就提供一个类来实现吧:
public class JsonHelper
{
private const string INDENT_STRING = " ";
public static string FormatJson(string str)
{
var indent = 0;
var quoted = false;
var sb = new StringBuilder();
for (var i = 0; i < str.Length; i++)
{
var ch = str[i];
switch (ch)
{
case '{':
case '[':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, ++indent).MyForEach(item => sb.Append(INDENT_STRING));
}
break;
case '}':
case ']':
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, --indent).MyForEach(item => sb.Append(INDENT_STRING));
}
sb.Append(ch);
break;
case '"':
sb.Append(ch);
bool escaped = false;
var index = i;
while (index > 0 && str[--index] == '\\')
escaped = !escaped;
if (!escaped)
quoted = !quoted;
break;
case ',':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, indent).MyForEach(item => sb.Append(INDENT_STRING));
}
break;
case ':':
sb.Append(ch);
if (!quoted)
sb.Append(" ");
break;
default:
sb.Append(ch);
break;
}
}
return sb.ToString();
}
}
static class Extensions
{
public static void MyForEach<T>(this IEnumerable<T> ie, Action<T> action)
{
foreach (var i in ie)
{
action(i);
}
}
}
作者:宋桓公
出处:http://www.cnblogs.com/douzi2/
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。