小技巧 - JSON 免定義物件 LINQ 操作
0 |
同事問到,由某 WebAPI 接回 JSON 格式的多筆資料,是否一定要定義強型別物件並搭配 JsonConvert.DeserializeObject<T[]> 才能用 LINQ 進行查詢整理?
答案是不用,有更省事的寫法。
如果只打算取用一兩欄位,且接入後會馬上轉成 Dictionary<T, T>、List<T> 等形式,為此額外宣告類別純屬浪費,不符合精實軟體開發精神。Json.NET 的 JObject LINQ 支援,在這種情境特別管用。
後面會應用以下觀念,印象模糊的同學可先複習:
假設資料源 JSON 長這樣:
[
{
"Name": "Jefrey",
"RegDate": "2018-01-01T00:00:00Z",
"Scores": [ 1, 9, 4, 2 ]
},
{
"Name": "Darkthread",
"RegDate": "2018-07-01T00:00:00Z",
"Scores": [ 1, 2, 3, 4, 5 ]
},
{
"Name": "Fox",
"RegDate": "2019-01-01T00:00:00Z",
"Scores": [ 9, 4, 8, 7 ]
}
]
最終目標是接收 JSON 解析並先找出註冊日期在 2018/6/30 之後的人員,並計算其 Scores 平均值。
廢話不多說,直接看程式碼,說明寫在註解裡。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonLinq
{
class Program
{
static void Main(string[] args)
{
//不宣告強型別物件直接轉成JObject操作,並視為dynamic操作
//https://blog.darkthread.net/blog/json-net-and-dynamic/
dynamic[] data = JsonConvert.DeserializeObject<JObject[]>(
File.ReadAllText("data.json"));
//取得第一個元素物件
var x = data.First();
//印出屬性,由輸出結果其型別如同 string, DateTime 及 int[]
Console.WriteLine($@"
====== Object ======
Name: {x.Name}
RegDate: {x.RegDate}
Scores: {x.Scores}");
//但事實不然,其真正型別為 JValue 或 JArray,應用時需轉型
Console.WriteLine($@"
====== Type ======
Name ({x.Name.GetType()})
RegDate ({x.RegDate.GetType()})
Scores ({x.Scores.GetType()})
");
//以下來個 LINQ 範例,我們要找出 2018/6/30 後註冊者的分數平均
//結果以Dictionary<string, float>型別回傳
var d = new DateTime(2018, 6, 30);
var dict = data
//日期JValue可直接轉型為DateTime
.Where(o => ((DateTime) o.RegDate).CompareTo(d) > 0)
.ToDictionary(
o => (string) o.Name, //字串JValue也可直接轉型
o =>
{
//陣列先轉JArray再用Select轉成int[]
var scores = (o.Scores as JArray).Select(s => (int)s).ToArray();
return Math.Round(scores.Sum() * 1.0f / scores.Length, 1);
});
Console.WriteLine("****** Result ******");
Console.WriteLine(JsonConvert.SerializeObject(dict, Formatting.Indented));
Console.ReadLine();
}
}
}
執行結果如下:
====== Object ======
Name: Jefrey
RegDate: 2018/1/1 上午 12:00:00
Scores: [
1,
9,
4,
2
]
====== Type ======
Name (Newtonsoft.Json.Linq.JValue)
RegDate (Newtonsoft.Json.Linq.JValue)
Scores (Newtonsoft.Json.Linq.JArray)
****** Result ******
{
"Darkthread": 3.0,
"Fox": 7.0
}
學會這招,未來遇到接收 JSON 要立刻轉換形式的應用情境,就不用再花時間定義資料型別囉~
Tips of using Json.NET JObject feature to execute LINQ function on JSON without declaring strong type data entity.
Comments
Be the first to post a comment