以前就是一直使用 `Newtonsoft.Json` 用起來還是挺舒服的。由於 JSON 的應用越來越廣,現在. NET Core 都內置了 `System.Text.Json` 可以直接對 JSON 進行操作,不過兩個東西的體驗依然有點區別。 有時候我們會遇到的從第三方傳遞過來的 json str ...
以前就是一直使用 Newtonsoft.Json
用起來還是挺舒服的。由於 JSON 的應用越來越廣,現在. NET Core 都內置了 System.Text.Json
可以直接對 JSON 進行操作,不過兩個東西的體驗依然有點區別。
有時候我們會遇到的從第三方傳遞過來的 json string 對象,對其進行解析並不需要所有的欄位,只需要一個目標的欄位時,可以考慮使用匿名對象/動態對象對其反序列化。
之前的
Newtonsoft.Json
好像直接使用 dynamic,運用 JObject 進行處理,現在的不是那麼容易。下文代碼基於. NET 6,為了代碼整潔,實際配置了 PropertyNameCaseInsensitive = true,但是下麵代碼中並沒有體現。
數據
我們定義瞭如下的類型,並從 OData 獲得了 str
字元串型數據。
public readonly static string str = """
{"@odata.context":"http://localhost:9000/api/v1/$metadata#DataDto","value":[{"id":"0b734ed7-2955-4af4-a902-35dc17871094","timestamp":1684839865920},{"id":"7e285d08-cdb3-4209-8335-0ff9b20d39ef","timestamp":1684836312421}]}
""";
public class DataDto
{
public string? Id { get; set; }
public long Timestamp { get; set; }
}
由於有元數據,我們無法直接將上面的字元串反序列化為 DataDto 的列表對象。
自定義類
最簡單的方式,是對應此類對象,設計一個只用於反序列化的新類。
public class ODataEnumerableResultWrapper<T>
where T : class
{
public IEnumerable<T> Value { get; set; }
}
var meta = JsonSerializer.Deserialize<ODataEnumerableResultWrapper<DataDto>>(str);
var target = meta.Value;
匿名方式
可以使用 JsonNode 來直接反序列化,並使用類似鍵值對的形式訪問。
public static void Main() {
JsonNode? meta = JsonSerializer.Deserialize<JsonNode>(str);
//如果直接是簡單的對象,而不是數組,可以使用GetValue<T>這種形式。
var count = meta?["value"]?.Deserialize<IEnumerable<DataDto>>().Count();
Console.WriteLine(count);
}
}
註意,這樣的操作和你反序列化為 JsonDocument/JsonElement 並沒有什麼本質的區別。
動態方式
由於設計區別,直接使用 dynamic 進行反序列化,得到的對象並不具有一般 dynamic 的性質(實際上是 System.Text.Json.JsonElement
對象)。因此,我們無法通過的 dynamic 訪問成員的形式進行操作。
dynamic meta = JsonSerializer.Deserialize<dynamic>(str);
Console.WriteLine(meta.GetType());
//OUTPUT: System.Text.Json.JsonElement
有 文章 說可以使用 ExpandoOject 實現,但是實際上無法對子級對象進行類似的訪問,因為獲取的子級對象,實際上是 JsonElement
。
dynamic meta = JsonSerializer.Deserialize<System.Dynamic.ExpandoObject>(str);
Console.WriteLine(meta.GetType());
//System.Dynamic.ExpandoObject
Console.WriteLine(meta.value);
//[{"id":"0b734ed7-2955-4af4-a902-35dc17871094","timestamp":1684839865920},{"id":"7e285d08-cdb3-4209-8335-0ff9b20d39ef","timestamp":1684836312421}]
Console.WriteLine(meta.value.GetType());
//System.Text.Json.JsonElement
當然可以通過自定義序列化的方式操作(見參考),但是這個辦法與我們的不寫額外代碼的初衷相衝突,因此不考慮了。