我有一個這樣的模型
private class CPDocs
{
public string DocumentDetails { get; set; }
public bool IsApproved { get; set; }
}
并且此類的 List 的一個實體包含這樣的資料
List<CPDocs> cd = new List<CPDocs>();
CPDocs cpd = new CPDocs();
cpd.DocumentDetails = "{\"name\":\"John\", \"age\":30, \"car\":null}";
cpd.IsApproved = false;
cd.Add(cpd);
(真實資料來自外部來源,我無法控制它。因此無法更改將資料添加到串列中的方式)
我想反序列化json字串并構造一個這樣的類。所以這DocumentDetails并IsApproved 附帶一個類的內部
public class person
{
public string name { get; set; }
public string age { get; set; }
public string car { get; set; }
public bool IsApproved { get; set; }
}
有沒有辦法使用 newtonsoft json 和 Linq 來實作這一點?
uj5u.com熱心網友回復:
讓我向您展示兩種不同的方式(一種簡單的實作方式和一種更高級的方式)
在我們開始之前
為了能夠測驗解決方案,我對您的課程進行了一些小改動
public class CPDocs
{
public string DocumentDetails { get; set; }
public bool IsApproved { get; set; }
}
public class Person
{
public string Name { get; set; }
public string Age { get; set; }
public string Car { get; set; }
public bool IsApproved { get; set; }
}
CPDocs變成了publicperson變成了PersonPerson使用 Pascal 套管的所有屬性
讓我們有一些示例資料來玩
List<CPDocs> cd = new()
{
new() { DocumentDetails = "{\"name\":\"John\", \"age\":30, \"car\":null}", IsApproved = false },
new() { DocumentDetails = "{\"name\":\"Jane\", \"age\":27, \"car\":null}", IsApproved = true },
new() { DocumentDetails = "{\"name\":\"Doe\", \"age\":null, \"car\":null}", IsApproved = false },
};
- 這里我使用了 object (for
CPDocs) 和 collection (forList<CPDocs>initializers以使物件創建更簡潔 - 我還使用了 C# 9 的Target-typed new 運算式(
new ()) 來使物件創建更加簡潔
天真的方法
var result = from doc in cd
let semiParsed = JObject.Parse(doc.DocumentDetails)
select new Person
{
Name = (string)semiParsed[nameof(Person.Name).ToLower()],
Age = (string)semiParsed[nameof(Person.Age).ToLower()],
Car = (string)semiParsed[nameof(Person.Car).ToLower()],
IsApproved = doc.IsApproved
};
foreach (var item in result)
Console.WriteLine($"{item.Name} ({item.Age}): '{item.Car}' {item.IsApproved}");
- 我在迭代期間引入了一個臨時變數,呼叫它
semiParsed來存盤半決議的 json - 有了這個
select宣告,我Person為每一個都創建了一個新的doc - 該
semiParsed指數運算子要求的欄位名稱- 因為我們在 C# 物件中使用了 Pascal Casing,在 json 中使用了 camel Casing,這就是為什么我們需要在它們之間定義一個轉換
nameof(Person.Age).ToLower() - 索引運算子回傳
JToken需要轉換為的string
- 因為我們在 C# 物件中使用了 Pascal Casing,在 json 中使用了 camel Casing,這就是為什么我們需要在它們之間定義一個轉換
(位)更高級的方法
上面的代碼很難維護,因為它是重復的((string)semiParsed[nameof(Person....).ToLower()])。
此外,如果 json 欄位和 C# 屬性名稱之間的映射不是那么簡單,該怎么辦?
讓我們從select陳述句中單獨定義一個映射
Dictionary<string, string> mapping = new()
{
{ nameof(Person.Name), "name" },
{ nameof(Person.Age), "age" },
{ nameof(Person.Car), "car" },
};
當然,如果您可以控制Person該類,那么您可能更喜歡JsonPropertyAttribute這個自定義映射。
我們還可以定義一個函式(或本地函式),它接收半決議的 json 和一個屬性選擇器(p => p.Name)并完成所有的魔法
string GetValueBasedOnSelector(JObject source, Expression<Func<Person, string>> propSelector)
{
var expression = (MemberExpression)propSelector.Body;
var propName = expression.Member.Name;
var fieldName = mapping[propName];
return (string)source[fieldName];
};
有了這個,Linq 查詢看起來像這樣:
result = from doc in cd
let semiParsed = JObject.Parse(doc.DocumentDetails)
select new Person
{
Name = GetValueBasedOnSelector(semiParsed, p => p.Name),
Age = GetValueBasedOnSelector(semiParsed, p => p.Age),
Car = GetValueBasedOnSelector(semiParsed, p => p.Car),
IsApproved = doc.IsApproved
};
uj5u.com熱心網友回復:
試試這個
person person = JsonConvert.DeserializeObject<person>(cpd.DocumentDetails);
person.IsApproved=cpd.IsApproved;
json格式的人
{
"name": "John",
"age": "30",
"car": null,
"IsApproved": false
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/405933.html
標籤:
下一篇:PowerShell中的LINQ
