我正在寻找适当地描述JSON中的列元数据的方法,稍后由Newtonsoft对其进行解析以构建C#DataTable。这样,我希望解决一个DataTable没有行或没有列的a的问题,但是即使我传递一个空表,我也需要使用标签和希望的数据类型来创建列。
DataTable
标准输入的示例:
{ "BrokerID": "998", "AccountID": "1313", "Packages": [ { "PackageID": 226, "Amount": 15000, "Auto_sync": true, "Color": "BLUE" }, { "PackageID": 500, "Amount": 15000, "Auto_sync": true, "Color": "PEACH" } ] }
输入表为空的示例:
{ "BrokerID" : "998", "AccountID" : "1313", "Packages":[] }
当我使用解析此内容时JsonConvert.DeserializeObject<DataTable>(params["Packages"]);,没有行,而且显然没有列。我正在寻找一种描述JSON正文中的列元数据的方法。
JsonConvert.DeserializeObject<DataTable>(params["Packages"]);
该DataTableConverter附带Json.Net不输出列的元数据,即使你设置TypeNameHandling到All。但是,没有什么可以阻止您制作自己的自定义转换器来执行此操作,而是使用该自定义转换器。以下是我根据您的需求拼凑而成的一种:
DataTableConverter
TypeNameHandling
All
class CustomDataTableConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(DataTable)); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { DataTable dt = (DataTable)value; JObject metaDataObj = new JObject(); foreach (DataColumn col in dt.Columns) { metaDataObj.Add(col.ColumnName, col.DataType.AssemblyQualifiedName); } JArray rowsArray = new JArray(); rowsArray.Add(metaDataObj); foreach (DataRow row in dt.Rows) { JObject rowDataObj = new JObject(); foreach (DataColumn col in dt.Columns) { rowDataObj.Add(col.ColumnName, JToken.FromObject(row[col])); } rowsArray.Add(rowDataObj); } rowsArray.WriteTo(writer); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JArray rowsArray = JArray.Load(reader); JObject metaDataObj = (JObject)rowsArray.First(); DataTable dt = new DataTable(); foreach (JProperty prop in metaDataObj.Properties()) { dt.Columns.Add(prop.Name, Type.GetType((string)prop.Value, throwOnError: true)); } foreach (JObject rowDataObj in rowsArray.Skip(1)) { DataRow row = dt.NewRow(); foreach (DataColumn col in dt.Columns) { if (rowDataObj[col.ColumnName].Type != JTokenType.Null)//Skip if the Value is Null/Missing, especially for a non-nullable type. row[col] = rowDataObj[col.ColumnName].ToObject(col.DataType); } dt.Rows.Add(row); } return dt; } }
这是一个演示。请注意,序列化表时,列类型被写为JSON中数组的第一行。反序列化时,即使没有其他行,此元数据也将用于使用正确的列类型和名称重建表。(您可以通过在顶部将行数据添加到表中的两行注释掉来验证这一点。)
class Program { static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("PackageID", typeof(int)); dt.Columns.Add("Amount", typeof(int)); dt.Columns.Add("Auto_sync", typeof(bool)); dt.Columns.Add("Color", typeof(string)); // Comment out these two lines to see the table with no data. // Test with a null Value for a Non-Nullable DataType. dt.Rows.Add(new object[] { 226, null, true, "BLUE" }); dt.Rows.Add(new object[] { 500, 15000, true, "PEACH" }); Foo foo = new Foo { BrokerID = "998", AccountID = "1313", Packages = dt }; JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Converters.Add(new CustomDataTableConverter()); settings.Formatting = Formatting.Indented; string json = JsonConvert.SerializeObject(foo, settings); Console.WriteLine(json); Console.WriteLine(); Foo foo2 = JsonConvert.DeserializeObject<Foo>(json, settings); Console.WriteLine("BrokerID: " + foo2.BrokerID); Console.WriteLine("AccountID: " + foo2.AccountID); Console.WriteLine("Packages table:"); Console.WriteLine(" " + string.Join(", ", foo2.Packages.Columns .Cast<DataColumn>() .Select(c => c.ColumnName + " (" + c.DataType.Name + ")"))); foreach (DataRow row in foo2.Packages.Rows) { Console.WriteLine(" " + string.Join(", ", row.ItemArray .Select(v => v != null ? v.ToString() : "(null)"))); } } } class Foo { public string BrokerID { get; set; } public string AccountID { get; set; } public DataTable Packages { get; set; } }
输出:
{ "BrokerID": "998", "AccountID": "1313", "Packages": [ { "PackageID": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Amount": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Auto_sync": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Color": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" }, { "PackageID": 226, "Amount": null, "Auto_sync": true, "Color": "BLUE" }, { "PackageID": 500, "Amount": 15000, "Auto_sync": true, "Color": "PEACH" } ] } BrokerID: 998 AccountID: 1313 Packages table: PackageID (Int32), Amount (Int32), Auto_sync (Boolean), Color (String) 226, , True, BLUE 500, 15000, True, PEACH
小提琴:https : //dotnetfiddle.net/GGrn9z